From 529c08555fd0b709a23d486211d28fbd0980fc94 Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 12 Jul 2018 22:04:38 -0400 Subject: [PATCH 01/40] Rename EventsLoop and associated types to EventLoop --- examples/cursor.rs | 2 +- examples/cursor_grab.rs | 2 +- examples/fullscreen.rs | 2 +- examples/handling_close.rs | 2 +- examples/min_max_size.rs | 2 +- examples/monitor_list.rs | 2 +- examples/multiwindow.rs | 2 +- examples/proxy.rs | 2 +- examples/resizable.rs | 2 +- examples/transparent.rs | 2 +- examples/window.rs | 2 +- examples/window_icon.rs | 2 +- src/lib.rs | 86 ++++++++++++------------ src/os/android.rs | 8 +-- src/os/unix.rs | 26 +++---- src/os/windows.rs | 16 ++--- src/platform/android/mod.rs | 20 +++--- src/platform/emscripten/mod.rs | 18 ++--- src/platform/ios/mod.rs | 18 ++--- src/platform/linux/mod.rs | 82 +++++++++++----------- src/platform/linux/wayland/event_loop.rs | 56 +++++++-------- src/platform/linux/wayland/keyboard.rs | 4 +- src/platform/linux/wayland/mod.rs | 2 +- src/platform/linux/wayland/pointer.rs | 4 +- src/platform/linux/wayland/touch.rs | 4 +- src/platform/linux/wayland/window.rs | 4 +- src/platform/linux/x11/mod.rs | 28 ++++---- src/platform/linux/x11/window.rs | 4 +- src/platform/macos/events_loop.rs | 16 ++--- src/platform/macos/mod.rs | 4 +- src/platform/macos/monitor.rs | 4 +- src/platform/macos/window.rs | 6 +- src/platform/windows/events_loop.rs | 28 ++++---- src/platform/windows/mod.rs | 2 +- src/platform/windows/monitor.rs | 4 +- src/platform/windows/window.rs | 11 ++- src/window.rs | 10 +-- tests/send_objects.rs | 4 +- 38 files changed, 246 insertions(+), 247 deletions(-) diff --git a/examples/cursor.rs b/examples/cursor.rs index d2df71a7af..2eb5e8cbad 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -3,7 +3,7 @@ extern crate winit; use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow}; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new().build(&events_loop).unwrap(); window.set_title("A fantastic window!"); diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index 641a324ded..d36ef72a79 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new() .with_title("Super Cursor Grab'n'Hide Simulator 9000") diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index a6cb5b6880..c4cebca36a 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -4,7 +4,7 @@ use std::io::{self, Write}; use winit::{ControlFlow, Event, WindowEvent}; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); // enumerating monitors let monitor = { diff --git a/examples/handling_close.rs b/examples/handling_close.rs index 101f45cf32..3b4add4069 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let _window = winit::WindowBuilder::new() .with_title("Your faithful window") diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index 06f4aa18d2..836820e7fe 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -3,7 +3,7 @@ extern crate winit; use winit::dpi::LogicalSize; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new() .build(&events_loop) diff --git a/examples/monitor_list.rs b/examples/monitor_list.rs index e40ac30918..635f2fb808 100644 --- a/examples/monitor_list.rs +++ b/examples/monitor_list.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let event_loop = winit::EventsLoop::new(); + let event_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new().build(&event_loop).unwrap(); println!("{:#?}\nPrimary: {:#?}", window.get_available_monitors(), window.get_primary_monitor()); } diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index b558aa231a..5b1d75a96f 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -3,7 +3,7 @@ extern crate winit; use std::collections::HashMap; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let mut windows = HashMap::new(); for _ in 0..3 { diff --git a/examples/proxy.rs b/examples/proxy.rs index a975181503..8518c1e210 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let _window = winit::WindowBuilder::new() .with_title("A fantastic window!") diff --git a/examples/resizable.rs b/examples/resizable.rs index 749e852121..fab1c65c8a 100644 --- a/examples/resizable.rs +++ b/examples/resizable.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let mut resizable = false; diff --git a/examples/transparent.rs b/examples/transparent.rs index a558350f3e..c5be1f2330 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new().with_decorations(false) .with_transparency(true) diff --git a/examples/window.rs b/examples/window.rs index fcc7d9ea33..2b9803378b 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let _window = winit::WindowBuilder::new() .with_title("A fantastic window!") diff --git a/examples/window_icon.rs b/examples/window_icon.rs index 5be1433e01..4cd9029c16 100644 --- a/examples/window_icon.rs +++ b/examples/window_icon.rs @@ -20,7 +20,7 @@ fn main() { // feature enabled). let icon = Icon::from_path(path).expect("Failed to open icon"); - let mut events_loop = winit::EventsLoop::new(); + let mut events_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new() .with_title("An iconic window!") diff --git a/src/lib.rs b/src/lib.rs index 0d2b59fa41..78874f2b45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,12 @@ //! //! # Building a window //! -//! Before you can build a window, you first need to build an `EventsLoop`. This is done with the -//! `EventsLoop::new()` function. Example: +//! Before you can build a window, you first need to build an `EventLoop`. This is done with the +//! `EventLoop::new()` function. Example: //! //! ```no_run -//! use winit::EventsLoop; -//! let events_loop = EventsLoop::new(); +//! use winit::EventLoop; +//! let events_loop = EventLoop::new(); //! ``` //! //! Once this is done there are two ways to create a window: @@ -25,7 +25,7 @@ //! Once a window has been created, it will *generate events*. For example whenever the user moves //! the window, resizes the window, moves the mouse, etc. an event is generated. //! -//! The events generated by a window can be retrieved from the `EventsLoop` the window was created +//! The events generated by a window can be retreived from the `EventLoop` the window was created //! with. //! //! There are two ways to do so. The first is to call `events_loop.poll_events(...)`, which will @@ -36,8 +36,8 @@ //! ```no_run //! use winit::{Event, WindowEvent}; //! use winit::dpi::LogicalSize; -//! # use winit::EventsLoop; -//! # let mut events_loop = EventsLoop::new(); +//! # use winit::EventLoop; +//! # let mut events_loop = EventLoop::new(); //! //! loop { //! events_loop.poll_events(|event| { @@ -59,8 +59,8 @@ //! //! ```no_run //! use winit::{ControlFlow, Event, WindowEvent}; -//! # use winit::EventsLoop; -//! # let mut events_loop = EventsLoop::new(); +//! # use winit::EventLoop; +//! # let mut events_loop = EventLoop::new(); //! //! events_loop.run_forever(|event| { //! match event { @@ -134,9 +134,9 @@ pub mod os; /// # Example /// /// ```no_run -/// use winit::{Event, EventsLoop, Window, WindowEvent, ControlFlow}; +/// use winit::{Event, EventLoop, Window, WindowEvent, ControlFlow}; /// -/// let mut events_loop = EventsLoop::new(); +/// let mut events_loop = EventLoop::new(); /// let window = Window::new(&events_loop).unwrap(); /// /// events_loop.run_forever(|event| { @@ -178,28 +178,28 @@ pub struct DeviceId(platform::DeviceId); /// Provides a way to retrieve events from the system and from the windows that were registered to /// the events loop. /// -/// An `EventsLoop` can be seen more or less as a "context". Calling `EventsLoop::new()` +/// An `EventLoop` can be seen more or less as a "context". Calling `EventLoop::new()` /// initializes everything that will be required to create windows. For example on Linux creating /// an events loop opens a connection to the X or Wayland server. /// -/// To wake up an `EventsLoop` from a another thread, see the `EventsLoopProxy` docs. +/// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs. /// -/// Note that the `EventsLoop` cannot be shared accross threads (due to platform-dependant logic +/// Note that the `EventLoop` cannot be shared accross threads (due to platform-dependant logic /// forbiding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the -/// `Window` created from this `EventsLoop` _can_ be sent to an other thread, and the -/// `EventsLoopProxy` allows you to wakeup an `EventsLoop` from an other thread. -pub struct EventsLoop { - events_loop: platform::EventsLoop, +/// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the +/// `EventLoopProxy` allows you to wakeup an `EventLoop` from an other thread. +pub struct EventLoop { + events_loop: platform::EventLoop, _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync } -impl std::fmt::Debug for EventsLoop { +impl std::fmt::Debug for EventLoop { fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { - fmtr.pad("EventsLoop { .. }") + fmtr.pad("EventLoop { .. }") } } -/// Returned by the user callback given to the `EventsLoop::run_forever` method. +/// Returned by the user callback given to the `EventLoop::run_forever` method. /// /// Indicates whether the `run_forever` method should continue or complete. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -211,16 +211,16 @@ pub enum ControlFlow { Break, } -impl EventsLoop { +impl EventLoop { /// Builds a new events loop. /// /// Usage will result in display backend initialisation, this can be controlled on linux /// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`. /// If it is not set, winit will try to connect to a wayland connection, and if it fails will /// fallback on x11. If this variable is set with any other value, winit will panic. - pub fn new() -> EventsLoop { - EventsLoop { - events_loop: platform::EventsLoop::new(), + pub fn new() -> EventLoop { + EventLoop { + events_loop: platform::EventLoop::new(), _marker: ::std::marker::PhantomData, } } @@ -264,52 +264,52 @@ impl EventsLoop { self.events_loop.run_forever(callback) } - /// Creates an `EventsLoopProxy` that can be used to wake up the `EventsLoop` from another + /// Creates an `EventLoopProxy` that can be used to wake up the `EventLoop` from another /// thread. - pub fn create_proxy(&self) -> EventsLoopProxy { - EventsLoopProxy { + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { events_loop_proxy: self.events_loop.create_proxy(), } } } -/// Used to wake up the `EventsLoop` from another thread. +/// Used to wake up the `EventLoop` from another thread. #[derive(Clone)] -pub struct EventsLoopProxy { - events_loop_proxy: platform::EventsLoopProxy, +pub struct EventLoopProxy { + events_loop_proxy: platform::EventLoopProxy, } -impl std::fmt::Debug for EventsLoopProxy { +impl std::fmt::Debug for EventLoopProxy { fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { - fmtr.pad("EventsLoopProxy { .. }") + fmtr.pad("EventLoopProxy { .. }") } } -impl EventsLoopProxy { - /// Wake up the `EventsLoop` from which this proxy was created. +impl EventLoopProxy { + /// Wake up the `EventLoop` from which this proxy was created. /// - /// This causes the `EventsLoop` to emit an `Awakened` event. + /// This causes the `EventLoop` to emit an `Awakened` event. /// - /// Returns an `Err` if the associated `EventsLoop` no longer exists. - pub fn wakeup(&self) -> Result<(), EventsLoopClosed> { + /// Returns an `Err` if the associated `EventLoop` no longer exists. + pub fn wakeup(&self) -> Result<(), EventLoopClosed> { self.events_loop_proxy.wakeup() } } -/// The error that is returned when an `EventsLoopProxy` attempts to wake up an `EventsLoop` that +/// The error that is returned when an `EventLoopProxy` attempts to wake up an `EventLoop` that /// no longer exists. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct EventsLoopClosed; +pub struct EventLoopClosed; -impl std::fmt::Display for EventsLoopClosed { +impl std::fmt::Display for EventLoopClosed { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", std::error::Error::description(self)) } } -impl std::error::Error for EventsLoopClosed { +impl std::error::Error for EventLoopClosed { fn description(&self) -> &str { - "Tried to wake up a closed `EventsLoop`" + "Tried to wake up a closed `EventLoop`" } } diff --git a/src/os/android.rs b/src/os/android.rs index 06661a325e..2efe95c1d3 100644 --- a/src/os/android.rs +++ b/src/os/android.rs @@ -1,17 +1,17 @@ #![cfg(any(target_os = "android"))] use std::os::raw::c_void; -use EventsLoop; +use EventLoop; use Window; use WindowBuilder; -/// Additional methods on `EventsLoop` that are specific to Android. -pub trait EventsLoopExt { +/// Additional methods on `EventLoop` that are specific to Android. +pub trait EventLoopExt { /// Makes it possible for glutin to register a callback when a suspend event happens on Android fn set_suspend_callback(&self, cb: Option ()>>); } -impl EventsLoopExt for EventsLoop { +impl EventLoopExt for EventLoop { fn set_suspend_callback(&self, cb: Option ()>>) { self.events_loop.set_suspend_callback(cb); } diff --git a/src/os/unix.rs b/src/os/unix.rs index e166da739b..9c2e446707 100644 --- a/src/os/unix.rs +++ b/src/os/unix.rs @@ -5,14 +5,14 @@ use std::ptr; use std::sync::Arc; use { - EventsLoop, + EventLoop, LogicalSize, MonitorId, Window, WindowBuilder, }; use platform::{ - EventsLoop as LinuxEventsLoop, + EventLoop as LinuxEventLoop, Window as LinuxWindow, }; use platform::x11::XConnection; @@ -25,31 +25,31 @@ pub use platform::x11; pub use platform::XNotSupported; pub use platform::x11::util::WindowType as XWindowType; -/// Additional methods on `EventsLoop` that are specific to Linux. -pub trait EventsLoopExt { - /// Builds a new `EventsLoop` that is forced to use X11. +/// Additional methods on `EventLoop` that are specific to Linux. +pub trait EventLoopExt { + /// Builds a new `EventLoop` that is forced to use X11. fn new_x11() -> Result where Self: Sized; - /// Builds a new `EventsLoop` that is forced to use Wayland. + /// Builds a new `EventLoop` that is forced to use Wayland. fn new_wayland() -> Self where Self: Sized; - /// True if the `EventsLoop` uses Wayland. + /// True if the `EventLoop` uses Wayland. fn is_wayland(&self) -> bool; - /// True if the `EventsLoop` uses X11. + /// True if the `EventLoop` uses X11. fn is_x11(&self) -> bool; #[doc(hidden)] fn get_xlib_xconnection(&self) -> Option>; } -impl EventsLoopExt for EventsLoop { +impl EventLoopExt for EventLoop { #[inline] fn new_x11() -> Result { - LinuxEventsLoop::new_x11().map(|ev| - EventsLoop { + LinuxEventLoop::new_x11().map(|ev| + EventLoop { events_loop: ev, _marker: ::std::marker::PhantomData, } @@ -58,8 +58,8 @@ impl EventsLoopExt for EventsLoop { #[inline] fn new_wayland() -> Self { - EventsLoop { - events_loop: match LinuxEventsLoop::new_wayland() { + EventLoop { + events_loop: match LinuxEventLoop::new_wayland() { Ok(e) => e, Err(_) => panic!() // TODO: propagate }, diff --git a/src/os/windows.rs b/src/os/windows.rs index 62b16c7aca..41e3ac1c4c 100644 --- a/src/os/windows.rs +++ b/src/os/windows.rs @@ -5,21 +5,21 @@ use std::os::raw::c_void; use libc; use winapi::shared::windef::HWND; -use {DeviceId, EventsLoop, Icon, MonitorId, Window, WindowBuilder}; -use platform::EventsLoop as WindowsEventsLoop; +use {DeviceId, EventLoop, Icon, MonitorId, Window, WindowBuilder}; +use platform::EventLoop as WindowsEventLoop; -/// Additional methods on `EventsLoop` that are specific to Windows. -pub trait EventsLoopExt { +/// Additional methods on `EventLoop` that are specific to Windows. +pub trait EventLoopExt { /// By default, winit on Windows will attempt to enable process-wide DPI awareness. If that's - /// undesirable, you can create an `EventsLoop` using this function instead. + /// undesirable, you can create an `EventLoop` using this function instead. fn new_dpi_unaware() -> Self where Self: Sized; } -impl EventsLoopExt for EventsLoop { +impl EventLoopExt for EventLoop { #[inline] fn new_dpi_unaware() -> Self { - EventsLoop { - events_loop: WindowsEventsLoop::with_dpi_awareness(false), + EventLoop { + events_loop: WindowsEventLoop::with_dpi_awareness(false), _marker: ::std::marker::PhantomData, } } diff --git a/src/platform/android/mod.rs b/src/platform/android/mod.rs index 165c5459eb..9b4f76a896 100644 --- a/src/platform/android/mod.rs +++ b/src/platform/android/mod.rs @@ -26,19 +26,19 @@ use CreationError::OsError; use events::{Touch, TouchPhase}; use window::MonitorId as RootMonitorId; -pub struct EventsLoop { +pub struct EventLoop { event_rx: Receiver, suspend_callback: RefCell ()>>>, } #[derive(Clone)] -pub struct EventsLoopProxy; +pub struct EventLoopProxy; -impl EventsLoop { - pub fn new() -> EventsLoop { +impl EventLoop { + pub fn new() -> EventLoop { let (tx, rx) = channel(); android_glue::add_sender(tx); - EventsLoop { + EventLoop { event_rx: rx, suspend_callback: Default::default(), } @@ -155,13 +155,13 @@ impl EventsLoop { } } - pub fn create_proxy(&self) -> EventsLoopProxy { - EventsLoopProxy + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy } } -impl EventsLoopProxy { - pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> { +impl EventLoopProxy { + pub fn wakeup(&self) -> Result<(), ::EventLoopClosed> { android_glue::wake_event_loop(); Ok(()) } @@ -236,7 +236,7 @@ pub struct PlatformSpecificWindowBuilderAttributes; pub struct PlatformSpecificHeadlessBuilderAttributes; impl Window { - pub fn new(_: &EventsLoop, win_attribs: WindowAttributes, + pub fn new(_: &EventLoop, win_attribs: WindowAttributes, _: PlatformSpecificWindowBuilderAttributes) -> Result { diff --git a/src/platform/emscripten/mod.rs b/src/platform/emscripten/mod.rs index a3d25ef1bf..0fb85a2e54 100644 --- a/src/platform/emscripten/mod.rs +++ b/src/platform/emscripten/mod.rs @@ -75,22 +75,22 @@ pub fn set_main_loop_callback(callback : F) where F : FnMut() { } #[derive(Clone)] -pub struct EventsLoopProxy; +pub struct EventLoopProxy; -impl EventsLoopProxy { - pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> { +impl EventLoopProxy { + pub fn wakeup(&self) -> Result<(), ::EventLoopClosed> { unimplemented!() } } -pub struct EventsLoop { +pub struct EventLoop { window: Mutex>>, interrupted: AtomicBool, } -impl EventsLoop { - pub fn new() -> EventsLoop { - EventsLoop { +impl EventLoop { + pub fn new() -> EventLoop { + EventLoop { window: Mutex::new(None), interrupted: AtomicBool::new(false), } @@ -102,7 +102,7 @@ impl EventsLoop { } #[inline] - pub fn create_proxy(&self) -> EventsLoopProxy { + pub fn create_proxy(&self) -> EventLoopProxy { unimplemented!() } @@ -366,7 +366,7 @@ fn em_try(res: ffi::EMSCRIPTEN_RESULT) -> Result<(), String> { } impl Window { - pub fn new(events_loop: &EventsLoop, attribs: ::WindowAttributes, + pub fn new(events_loop: &EventLoop, attribs: ::WindowAttributes, _pl_attribs: PlatformSpecificWindowBuilderAttributes) -> Result { diff --git a/src/platform/ios/mod.rs b/src/platform/ios/mod.rs index 1c8e7c8535..afdbcef357 100644 --- a/src/platform/ios/mod.rs +++ b/src/platform/ios/mod.rs @@ -204,13 +204,13 @@ pub struct EventsLoop { } #[derive(Clone)] -pub struct EventsLoopProxy; +pub struct EventLoopProxy; -impl EventsLoop { - pub fn new() -> EventsLoop { +impl EventLoop { + pub fn new() -> EventLoop { unsafe { if !msg_send![class!(NSThread), isMainThread] { - panic!("`EventsLoop` can only be created on the main thread on iOS"); + panic!("`EventLoop` can only be created on the main thread on iOS"); } } EventsLoop { events_queue: Default::default() } @@ -276,13 +276,13 @@ impl EventsLoop { } } - pub fn create_proxy(&self) -> EventsLoopProxy { - EventsLoopProxy + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy } } -impl EventsLoopProxy { - pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> { +impl EventLoopProxy { + pub fn wakeup(&self) -> Result<(), ::EventLoopClosed> { unimplemented!() } } @@ -310,7 +310,7 @@ impl Default for PlatformSpecificWindowBuilderAttributes { // so to be consistent with other platforms we have to change that. impl Window { pub fn new( - ev: &EventsLoop, + ev: &EventLoop, _attributes: WindowAttributes, pl_attributes: PlatformSpecificWindowBuilderAttributes, ) -> Result { diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 65eabe1e5e..dd9d4a1026 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -11,7 +11,7 @@ use sctk::reexports::client::ConnectError; use { CreationError, - EventsLoopClosed, + EventLoopClosed, Icon, MouseCursor, ControlFlow, @@ -122,15 +122,15 @@ impl MonitorId { impl Window { #[inline] pub fn new( - events_loop: &EventsLoop, + events_loop: &EventLoop, attribs: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes, ) -> Result { match *events_loop { - EventsLoop::Wayland(ref events_loop) => { + EventLoop::Wayland(ref events_loop) => { wayland::Window::new(events_loop, attribs).map(Window::Wayland) }, - EventsLoop::X(ref events_loop) => { + EventLoop::X(ref events_loop) => { x11::Window::new(events_loop, attribs, pl_attribs).map(Window::X) }, } @@ -389,27 +389,27 @@ unsafe extern "C" fn x_error_callback( 0 } -pub enum EventsLoop { - Wayland(wayland::EventsLoop), - X(x11::EventsLoop) +pub enum EventLoop { + Wayland(wayland::EventLoop), + X(x11::EventLoop) } #[derive(Clone)] -pub enum EventsLoopProxy { - X(x11::EventsLoopProxy), - Wayland(wayland::EventsLoopProxy), +pub enum EventLoopProxy { + X(x11::EventLoopProxy), + Wayland(wayland::EventLoopProxy), } -impl EventsLoop { - pub fn new() -> EventsLoop { +impl EventLoop { + pub fn new() -> EventLoop { if let Ok(env_var) = env::var(BACKEND_PREFERENCE_ENV_VAR) { match env_var.as_str() { "x11" => { // TODO: propagate - return EventsLoop::new_x11().expect("Failed to initialize X11 backend"); + return EventLoop::new_x11().expect("Failed to initialize X11 backend"); }, "wayland" => { - return EventsLoop::new_wayland() + return EventLoop::new_wayland() .expect("Failed to initialize Wayland backend"); }, _ => panic!( @@ -419,12 +419,12 @@ impl EventsLoop { } } - let wayland_err = match EventsLoop::new_wayland() { + let wayland_err = match EventLoop::new_wayland() { Ok(event_loop) => return event_loop, Err(err) => err, }; - let x11_err = match EventsLoop::new_x11() { + let x11_err = match EventLoop::new_x11() { Ok(event_loop) => return event_loop, Err(err) => err, }; @@ -437,30 +437,30 @@ impl EventsLoop { panic!(err_string); } - pub fn new_wayland() -> Result { - wayland::EventsLoop::new() - .map(EventsLoop::Wayland) + pub fn new_wayland() -> Result { + wayland::EventLoop::new() + .map(EventLoop::Wayland) } - pub fn new_x11() -> Result { + pub fn new_x11() -> Result { X11_BACKEND .lock() .as_ref() .map(Arc::clone) - .map(x11::EventsLoop::new) - .map(EventsLoop::X) + .map(x11::EventLoop::new) + .map(EventLoop::X) .map_err(|err| err.clone()) } #[inline] pub fn get_available_monitors(&self) -> VecDeque { match *self { - EventsLoop::Wayland(ref evlp) => evlp + EventLoop::Wayland(ref evlp) => evlp .get_available_monitors() .into_iter() .map(MonitorId::Wayland) .collect(), - EventsLoop::X(ref evlp) => evlp + EventLoop::X(ref evlp) => evlp .x_connection() .get_available_monitors() .into_iter() @@ -472,15 +472,15 @@ impl EventsLoop { #[inline] pub fn get_primary_monitor(&self) -> MonitorId { match *self { - EventsLoop::Wayland(ref evlp) => MonitorId::Wayland(evlp.get_primary_monitor()), - EventsLoop::X(ref evlp) => MonitorId::X(evlp.x_connection().get_primary_monitor()), + EventLoop::Wayland(ref evlp) => MonitorId::Wayland(evlp.get_primary_monitor()), + EventLoop::X(ref evlp) => MonitorId::X(evlp.x_connection().get_primary_monitor()), } } - pub fn create_proxy(&self) -> EventsLoopProxy { + pub fn create_proxy(&self) -> EventLoopProxy { match *self { - EventsLoop::Wayland(ref evlp) => EventsLoopProxy::Wayland(evlp.create_proxy()), - EventsLoop::X(ref evlp) => EventsLoopProxy::X(evlp.create_proxy()), + EventLoop::Wayland(ref evlp) => EventLoopProxy::Wayland(evlp.create_proxy()), + EventLoop::X(ref evlp) => EventLoopProxy::X(evlp.create_proxy()), } } @@ -488,8 +488,8 @@ impl EventsLoop { where F: FnMut(::Event) { match *self { - EventsLoop::Wayland(ref mut evlp) => evlp.poll_events(callback), - EventsLoop::X(ref mut evlp) => evlp.poll_events(callback) + EventLoop::Wayland(ref mut evlp) => evlp.poll_events(callback), + EventLoop::X(ref mut evlp) => evlp.poll_events(callback) } } @@ -497,33 +497,33 @@ impl EventsLoop { where F: FnMut(::Event) -> ControlFlow { match *self { - EventsLoop::Wayland(ref mut evlp) => evlp.run_forever(callback), - EventsLoop::X(ref mut evlp) => evlp.run_forever(callback) + EventLoop::Wayland(ref mut evlp) => evlp.run_forever(callback), + EventLoop::X(ref mut evlp) => evlp.run_forever(callback) } } #[inline] pub fn is_wayland(&self) -> bool { match *self { - EventsLoop::Wayland(_) => true, - EventsLoop::X(_) => false, + EventLoop::Wayland(_) => true, + EventLoop::X(_) => false, } } #[inline] pub fn x_connection(&self) -> Option<&Arc> { match *self { - EventsLoop::Wayland(_) => None, - EventsLoop::X(ref ev) => Some(ev.x_connection()), + EventLoop::Wayland(_) => None, + EventLoop::X(ref ev) => Some(ev.x_connection()), } } } -impl EventsLoopProxy { - pub fn wakeup(&self) -> Result<(), EventsLoopClosed> { +impl EventLoopProxy { + pub fn wakeup(&self) -> Result<(), EventLoopClosed> { match *self { - EventsLoopProxy::Wayland(ref proxy) => proxy.wakeup(), - EventsLoopProxy::X(ref proxy) => proxy.wakeup(), + EventLoopProxy::Wayland(ref proxy) => proxy.wakeup(), + EventLoopProxy::X(ref proxy) => proxy.wakeup(), } } } diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index edf35f075b..50c8d2ebb7 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -4,7 +4,7 @@ use std::fmt; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex, Weak}; -use {ControlFlow, EventsLoopClosed, PhysicalPosition, PhysicalSize}; +use {ControlFlow, EventLoopClosed, PhysicalPosition, PhysicalSize}; use super::window::WindowStore; use super::WindowId; @@ -21,13 +21,13 @@ use sctk::reexports::client::protocol::wl_surface::RequestsTrait; use ModifiersState; -pub struct EventsLoopSink { +pub struct EventLoopSink { buffer: VecDeque<::Event>, } -impl EventsLoopSink { - pub fn new() -> EventsLoopSink { - EventsLoopSink { +impl EventLoopSink { + pub fn new() -> EventLoopSink { + EventLoopSink { buffer: VecDeque::new(), } } @@ -54,11 +54,11 @@ impl EventsLoopSink { } } -pub struct EventsLoop { +pub struct EventLoop { // The Event Queue pub evq: RefCell, // our sink, shared with some handlers, buffering the events - sink: Arc>, + sink: Arc>, // Whether or not there is a pending `Awakened` event to be emitted. pending_wakeup: Arc, // The window store @@ -73,43 +73,43 @@ pub struct EventsLoop { pub seats: Arc)>>>, } -// A handle that can be sent across threads and used to wake up the `EventsLoop`. +// A handle that can be sent across threads and used to wake up the `EventLoop`. // -// We should only try and wake up the `EventsLoop` if it still exists, so we hold Weak ptrs. +// We should only try and wake up the `EventLoop` if it still exists, so we hold Weak ptrs. #[derive(Clone)] -pub struct EventsLoopProxy { +pub struct EventLoopProxy { display: Weak, pending_wakeup: Weak, } -impl EventsLoopProxy { - // Causes the `EventsLoop` to stop blocking on `run_forever` and emit an `Awakened` event. +impl EventLoopProxy { + // Causes the `EventLoop` 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> { + // Returns `Err` if the associated `EventLoop` no longer exists. + pub fn wakeup(&self) -> Result<(), EventLoopClosed> { let display = self.display.upgrade(); let wakeup = self.pending_wakeup.upgrade(); match (display, wakeup) { (Some(display), Some(wakeup)) => { - // Update the `EventsLoop`'s `pending_wakeup` flag. + // Update the `EventLoop`'s `pending_wakeup` flag. wakeup.store(true, Ordering::Relaxed); - // Cause the `EventsLoop` to break from `dispatch` if it is currently blocked. + // Cause the `EventLoop` to break from `dispatch` if it is currently blocked. let _ = display.sync(|callback| callback.implement(|_, _| {}, ())); - display.flush().map_err(|_| EventsLoopClosed)?; + display.flush().map_err(|_| EventLoopClosed)?; Ok(()) } - _ => Err(EventsLoopClosed), + _ => Err(EventLoopClosed), } } } -impl EventsLoop { - pub fn new() -> Result { +impl EventLoop { + pub fn new() -> Result { let (display, mut event_queue) = Display::connect_to_env()?; let display = Arc::new(display); let pending_wakeup = Arc::new(AtomicBool::new(false)); - let sink = Arc::new(Mutex::new(EventsLoopSink::new())); + let sink = Arc::new(Mutex::new(EventLoopSink::new())); let store = Arc::new(Mutex::new(WindowStore::new())); let seats = Arc::new(Mutex::new(Vec::new())); @@ -126,7 +126,7 @@ impl EventsLoop { let env = Environment::from_display_with_cb( &display, &mut event_queue, - move |event, registry| { + move |event, registry| { seat_manager.receive(event, registry) }, ).unwrap(); @@ -143,8 +143,8 @@ impl EventsLoop { }) } - pub fn create_proxy(&self) -> EventsLoopProxy { - EventsLoopProxy { + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { display: Arc::downgrade(&self.display), pending_wakeup: Arc::downgrade(&self.pending_wakeup), } @@ -221,10 +221,10 @@ impl EventsLoop { } /* - * Private EventsLoop Internals + * Private EventLoop Internals */ -impl EventsLoop { +impl EventLoop { fn post_dispatch_triggers(&mut self) { let mut sink = self.sink.lock().unwrap(); // process a possible pending wakeup call @@ -279,7 +279,7 @@ impl EventsLoop { */ struct SeatManager { - sink: Arc>, + sink: Arc>, store: Arc>, seats: Arc)>>>, events_loop_proxy: EventsLoopProxy, @@ -332,7 +332,7 @@ impl SeatManager { } struct SeatData { - sink: Arc>, + sink: Arc>, store: Arc>, pointer: Option>, keyboard: Option>, diff --git a/src/platform/linux/wayland/keyboard.rs b/src/platform/linux/wayland/keyboard.rs index 1b487120dc..30b60b1279 100644 --- a/src/platform/linux/wayland/keyboard.rs +++ b/src/platform/linux/wayland/keyboard.rs @@ -13,8 +13,8 @@ use {ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent}; pub fn init_keyboard( seat: &Proxy, - sink: Arc>, - events_loop_proxy: EventsLoopProxy, + sink: Arc>, + events_loop_proxy: EventLoopProxy, modifiers_tracker: Arc>, ) -> Proxy { // { variables to be captured by the closures diff --git a/src/platform/linux/wayland/mod.rs b/src/platform/linux/wayland/mod.rs index e938b8a749..aa3562f8c6 100644 --- a/src/platform/linux/wayland/mod.rs +++ b/src/platform/linux/wayland/mod.rs @@ -2,7 +2,7 @@ target_os = "netbsd", target_os = "openbsd"))] pub use self::window::Window; -pub use self::event_loop::{EventsLoop, EventsLoopProxy, EventsLoopSink, MonitorId}; +pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopSink, MonitorId}; use sctk::reexports::client::protocol::wl_surface; use sctk::reexports::client::Proxy; diff --git a/src/platform/linux/wayland/pointer.rs b/src/platform/linux/wayland/pointer.rs index ebe9d101dc..d910a5ea64 100644 --- a/src/platform/linux/wayland/pointer.rs +++ b/src/platform/linux/wayland/pointer.rs @@ -4,7 +4,7 @@ use {ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent}; use events::ModifiersState; use super::DeviceId; -use super::event_loop::EventsLoopSink; +use super::event_loop::EventLoopSink; use super::window::WindowStore; use sctk::reexports::client::Proxy; @@ -14,7 +14,7 @@ use sctk::reexports::client::protocol::wl_seat::RequestsTrait as SeatRequests; pub fn implement_pointer( seat: &Proxy, - sink: Arc>, + sink: Arc>, store: Arc>, modifiers_tracker: Arc>, ) -> Proxy { diff --git a/src/platform/linux/wayland/touch.rs b/src/platform/linux/wayland/touch.rs index e9e28d6154..a357f3aa0b 100644 --- a/src/platform/linux/wayland/touch.rs +++ b/src/platform/linux/wayland/touch.rs @@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex}; use {TouchPhase, WindowEvent}; use super::{DeviceId, WindowId}; -use super::event_loop::EventsLoopSink; +use super::event_loop::EventLoopSink; use super::window::WindowStore; use sctk::reexports::client::Proxy; @@ -19,7 +19,7 @@ struct TouchPoint { pub(crate) fn implement_touch( seat: &Proxy, - sink: Arc>, + sink: Arc>, store: Arc>, ) -> Proxy { let mut pending_ids = Vec::new(); diff --git a/src/platform/linux/wayland/window.rs b/src/platform/linux/wayland/window.rs index 6d9da8b0fb..42b7c52b83 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform/linux/wayland/window.rs @@ -13,7 +13,7 @@ use sctk::reexports::client::protocol::wl_compositor::RequestsTrait as Composito use sctk::reexports::client::protocol::wl_surface::RequestsTrait as SurfaceRequests; use sctk::output::OutputMgr; -use super::{make_wid, EventsLoop, MonitorId, WindowId}; +use super::{make_wid, EventLoop, MonitorId, WindowId}; use platform::platform::wayland::event_loop::{get_available_monitors, get_primary_monitor}; pub struct Window { @@ -28,7 +28,7 @@ pub struct Window { } impl Window { - pub fn new(evlp: &EventsLoop, attributes: WindowAttributes) -> Result { + pub fn new(evlp: &EventLoop, attributes: WindowAttributes) -> Result { let (width, height) = attributes.dimensions.map(Into::into).unwrap_or((800, 600)); // Create the window let size = Arc::new(Mutex::new((width, height))); diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index 461acde16f..c817aeadff 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -29,7 +29,7 @@ use { CreationError, DeviceEvent, Event, - EventsLoopClosed, + EventLoopClosed, KeyboardInput, LogicalPosition, LogicalSize, @@ -41,7 +41,7 @@ use platform::PlatformSpecificWindowBuilderAttributes; use self::dnd::{Dnd, DndState}; use self::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime}; -pub struct EventsLoop { +pub struct EventLoop { xconn: Arc, wm_delete_window: ffi::Atom, dnd: Dnd, @@ -60,14 +60,14 @@ pub struct EventsLoop { } #[derive(Clone)] -pub struct EventsLoopProxy { +pub struct EventLoopProxy { pending_wakeup: Weak, xconn: Weak, wakeup_dummy_window: ffi::Window, } -impl EventsLoop { - pub fn new(xconn: Arc) -> EventsLoop { +impl EventLoop { + pub fn new(xconn: Arc) -> EventLoop { let root = unsafe { (xconn.xlib.XDefaultRootWindow)(xconn.display) }; let wm_delete_window = unsafe { xconn.get_atom_unchecked(b"WM_DELETE_WINDOW\0") }; @@ -142,7 +142,7 @@ impl EventsLoop { ) }; - let result = EventsLoop { + let result = EventLoop { xconn, wm_delete_window, dnd, @@ -177,8 +177,8 @@ impl EventsLoop { &self.xconn } - pub fn create_proxy(&self) -> EventsLoopProxy { - EventsLoopProxy { + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { pending_wakeup: Arc::downgrade(&self.pending_wakeup), xconn: Arc::downgrade(&self.xconn), wakeup_dummy_window: self.wakeup_dummy_window, @@ -1181,15 +1181,15 @@ impl EventsLoop { } } -impl EventsLoopProxy { - pub fn wakeup(&self) -> Result<(), EventsLoopClosed> { - // Update the `EventsLoop`'s `pending_wakeup` flag. +impl EventLoopProxy { + pub fn wakeup(&self) -> Result<(), EventLoopClosed> { + // Update the `EventLoop`'s `pending_wakeup` flag. let display = match (self.pending_wakeup.upgrade(), self.xconn.upgrade()) { (Some(wakeup), Some(display)) => { wakeup.store(true, atomic::Ordering::Relaxed); display }, - _ => return Err(EventsLoopClosed), + _ => return Err(EventLoopClosed), }; // Push an event on the X event queue so that methods run_forever will advance. @@ -1269,7 +1269,7 @@ impl Deref for Window { impl Window { pub fn new( - event_loop: &EventsLoop, + event_loop: &EventLoop, attribs: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes ) -> Result { @@ -1354,7 +1354,7 @@ enum ScrollOrientation { } impl Device { - fn new(el: &EventsLoop, info: &ffi::XIDeviceInfo) -> Self { + fn new(el: &EventLoop, info: &ffi::XIDeviceInfo) -> Self { let name = unsafe { CStr::from_ptr(info.name).to_string_lossy() }; let mut scroll_axes = Vec::new(); diff --git a/src/platform/linux/x11/window.rs b/src/platform/linux/x11/window.rs index 6e73aca03e..a2b83c0289 100644 --- a/src/platform/linux/x11/window.rs +++ b/src/platform/linux/x11/window.rs @@ -15,7 +15,7 @@ use platform::PlatformSpecificWindowBuilderAttributes; use platform::x11::MonitorId as X11MonitorId; use window::MonitorId as RootMonitorId; -use super::{ffi, util, ImeSender, XConnection, XError, WindowId, EventsLoop}; +use super::{ffi, util, ImeSender, XConnection, XError, WindowId, EventLoop}; unsafe extern "C" fn visibility_predicate( _display: *mut ffi::Display, @@ -70,7 +70,7 @@ pub struct UnownedWindow { impl UnownedWindow { pub fn new( - event_loop: &EventsLoop, + event_loop: &EventLoop, window_attrs: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes, ) -> Result { diff --git a/src/platform/macos/events_loop.rs b/src/platform/macos/events_loop.rs index 7c5e69703e..f8f765bb2f 100644 --- a/src/platform/macos/events_loop.rs +++ b/src/platform/macos/events_loop.rs @@ -1,4 +1,4 @@ -use {ControlFlow, EventsLoopClosed}; +use {ControlFlow, EventLoopClosed}; use cocoa::{self, appkit, foundation}; use cocoa::appkit::{NSApplication, NSEvent, NSEventMask, NSEventModifierFlags, NSEventPhase, NSView, NSWindow}; use events::{self, ElementState, Event, TouchPhase, WindowEvent, DeviceEvent, ModifiersState, KeyboardInput}; @@ -9,12 +9,12 @@ use std; use std::os::raw::*; use super::DeviceId; -pub struct EventsLoop { +pub struct EventLoop { modifiers: Modifiers, pub shared: Arc, } -// State shared between the `EventsLoop` and its registered windows. +// State shared between the `EventLoop` and its registered windows. pub struct Shared { pub windows: Mutex>>, pub pending_events: Mutex>, @@ -42,7 +42,7 @@ struct Modifiers { // Wrapping the user callback in a type allows us to: // // - ensure the callback pointer is never accidentally cloned -// - ensure that only the `EventsLoop` can `store` and `drop` the callback pointer +// - ensure that only the `EventLoop` can `store` and `drop` the callback pointer // - Share access to the user callback with the NSWindow callbacks. pub struct UserCallback { mutex: Mutex>, @@ -160,17 +160,17 @@ impl UserCallback { } -impl EventsLoop { +impl EventLoop { pub fn new() -> Self { // Mark this thread as the main thread of the Cocoa event system. // // This must be done before any worker threads get a chance to call it - // (e.g., via `EventsLoopProxy::wakeup()`), causing a wrong thread to be + // (e.g., via `EventLoopProxy::wakeup()`), causing a wrong thread to be // marked as the main thread. unsafe { appkit::NSApp(); } - EventsLoop { + EventLoop { shared: Arc::new(Shared::new()), modifiers: Modifiers::new(), } @@ -521,7 +521,7 @@ impl EventsLoop { } impl Proxy { - pub fn wakeup(&self) -> Result<(), EventsLoopClosed> { + pub fn wakeup(&self) -> Result<(), EventLoopClosed> { // Awaken the event loop by triggering `NSApplicationActivatedEventType`. unsafe { let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil); diff --git a/src/platform/macos/mod.rs b/src/platform/macos/mod.rs index 9639482a7e..53d2a785ea 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, Proxy as EventsLoopProxy}; +pub use self::events_loop::{EventLoop, Proxy as EventLoopProxy}; pub use self::monitor::MonitorId; pub use self::window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, Window2}; use std::sync::Arc; @@ -24,7 +24,7 @@ impl ::std::ops::Deref for Window { impl Window { - pub fn new(events_loop: &EventsLoop, + pub fn new(events_loop: &EventLoop, attributes: ::WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes) -> Result { diff --git a/src/platform/macos/monitor.rs b/src/platform/macos/monitor.rs index c8786f9dce..062cf73c3f 100644 --- a/src/platform/macos/monitor.rs +++ b/src/platform/macos/monitor.rs @@ -7,7 +7,7 @@ use cocoa::foundation::{NSString, NSUInteger}; use core_graphics::display::{CGDirectDisplayID, CGDisplay, CGDisplayBounds}; use {PhysicalPosition, PhysicalSize}; -use super::EventsLoop; +use super::EventLoop; use super::window::{IdRef, Window2}; #[derive(Clone, PartialEq)] @@ -30,7 +30,7 @@ pub fn get_primary_monitor() -> MonitorId { id } -impl EventsLoop { +impl EventLoop { #[inline] pub fn get_available_monitors(&self) -> VecDeque { get_available_monitors() diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index 881002c345..26b14b3e25 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -42,7 +42,7 @@ use { use CreationError::OsError; use os::macos::{ActivationPolicy, WindowExt}; use platform::platform::{ffi, util}; -use platform::platform::events_loop::{EventsLoop, Shared}; +use platform::platform::events_loop::{EventLoop, Shared}; use platform::platform::view::{new_view, set_ime_spot}; use window::MonitorId as RootMonitorId; @@ -169,7 +169,7 @@ pub struct WindowDelegate { } impl WindowDelegate { - // Emits an event via the `EventsLoop`'s callback or stores it in the pending queue. + // Emits an event via the `EventLoop`'s callback or stores it in the pending queue. pub fn emit_event(state: &mut DelegateState, window_event: WindowEvent) { let window_id = get_window_id(*state.window); let event = Event::WindowEvent { @@ -543,7 +543,7 @@ unsafe fn get_current_monitor(window: id) -> RootMonitorId { let key = IdRef::new(NSString::alloc(nil).init_str("NSScreenNumber")); let value = NSDictionary::valueForKey_(desc, *key); let display_id = msg_send![value, unsignedIntegerValue]; - RootMonitorId { inner: EventsLoop::make_monitor_from_display(display_id) } + RootMonitorId { inner: EventLoop::make_monitor_from_display(display_id) } } impl Drop for Window2 { diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index b14faa1075..9ccd394ddf 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -40,7 +40,7 @@ use winapi::um::winnt::{LONG, LPCSTR, SHORT}; use { ControlFlow, Event, - EventsLoopClosed, + EventLoopClosed, KeyboardInput, LogicalPosition, LogicalSize, @@ -133,19 +133,19 @@ impl Inserter { } } -pub struct EventsLoop { +pub struct EventLoop { // Id of the background thread from the Win32 API. thread_id: DWORD, // Receiver for the events. The sender is in the background thread. receiver: mpsc::Receiver, } -impl EventsLoop { - pub fn new() -> EventsLoop { +impl EventLoop { + pub fn new() -> EventLoop { Self::with_dpi_awareness(true) } - pub fn with_dpi_awareness(dpi_aware: bool) -> EventsLoop { + pub fn with_dpi_awareness(dpi_aware: bool) -> EventLoop { become_dpi_aware(dpi_aware); // The main events transfer channel. @@ -211,7 +211,7 @@ impl EventsLoop { processthreadsapi::GetThreadId(handle) }; - EventsLoop { + EventLoop { thread_id, receiver: rx, } @@ -247,8 +247,8 @@ impl EventsLoop { } } - pub fn create_proxy(&self) -> EventsLoopProxy { - EventsLoopProxy { + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { thread_id: self.thread_id, } } @@ -267,7 +267,7 @@ impl EventsLoop { } } -impl Drop for EventsLoop { +impl Drop for EventLoop { fn drop(&mut self) { unsafe { // Posting `WM_QUIT` will cause `GetMessage` to stop. @@ -277,12 +277,12 @@ impl Drop for EventsLoop { } #[derive(Clone)] -pub struct EventsLoopProxy { +pub struct EventLoopProxy { thread_id: DWORD, } -impl EventsLoopProxy { - pub fn wakeup(&self) -> Result<(), EventsLoopClosed> { +impl EventLoopProxy { + pub fn wakeup(&self) -> Result<(), EventLoopClosed> { unsafe { if winuser::PostThreadMessageA(self.thread_id, *WAKEUP_MSG_ID, 0, 0) != 0 { Ok(()) @@ -294,7 +294,7 @@ impl EventsLoopProxy { // > idThread does not have a message queue. GetLastError returns // > ERROR_NOT_ENOUGH_QUOTA when the message limit is hit. // TODO: handle ERROR_NOT_ENOUGH_QUOTA - Err(EventsLoopClosed) + Err(EventLoopClosed) } } } @@ -335,7 +335,7 @@ impl EventsLoopProxy { } lazy_static! { - // Message sent by the `EventsLoopProxy` when we want to wake up the thread. + // Message sent by the `EventLoopProxy` when we want to wake up the thread. // WPARAM and LPARAM are unused. static ref WAKEUP_MSG_ID: u32 = { unsafe { diff --git a/src/platform/windows/mod.rs b/src/platform/windows/mod.rs index f7a576eb4d..0e981e091a 100644 --- a/src/platform/windows/mod.rs +++ b/src/platform/windows/mod.rs @@ -3,7 +3,7 @@ use winapi; use winapi::shared::windef::HWND; -pub use self::events_loop::{EventsLoop, EventsLoopProxy}; +pub use self::events_loop::{EventLoop, EventLoopProxy}; pub use self::monitor::MonitorId; pub use self::window::Window; diff --git a/src/platform/windows/monitor.rs b/src/platform/windows/monitor.rs index 30394de0a6..760d392456 100644 --- a/src/platform/windows/monitor.rs +++ b/src/platform/windows/monitor.rs @@ -6,7 +6,7 @@ use winapi::um::winuser; use std::{mem, ptr}; use std::collections::VecDeque; -use super::{EventsLoop, util}; +use super::{EventLoop, util}; use dpi::{PhysicalPosition, PhysicalSize}; use platform::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi}; use platform::platform::window::Window; @@ -71,7 +71,7 @@ pub fn get_primary_monitor() -> MonitorId { MonitorId::from_hmonitor(hmonitor) } -impl EventsLoop { +impl EventLoop { // TODO: Investigate opportunities for caching pub fn get_available_monitors(&self) -> VecDeque { get_available_monitors() diff --git a/src/platform/windows/window.rs b/src/platform/windows/window.rs index d7d789a13a..95c821e7a7 100644 --- a/src/platform/windows/window.rs +++ b/src/platform/windows/window.rs @@ -28,8 +28,7 @@ use { }; use platform::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, WindowId}; use platform::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi}; -use platform::platform::events_loop::{self, EventsLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID}; -use platform::platform::events_loop::WindowState; +use platform::platform::events_loop::{self, DESTROY_MSG_ID, EventLoop, INITIAL_DPI_MSG_ID, WindowState}; use platform::platform::icon::{self, IconType, WinIcon}; use platform::platform::monitor::get_available_monitors; use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input; @@ -46,7 +45,7 @@ pub struct Window { window_state: Arc>, // The events loop proxy. - events_loop_proxy: events_loop::EventsLoopProxy, + events_loop_proxy: events_loop::EventLoopProxy, } // https://blogs.msdn.microsoft.com/oldnewthing/20131017-00/?p=2903 @@ -73,7 +72,7 @@ unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> B impl Window { pub fn new( - events_loop: &EventsLoop, + events_loop: &EventLoop, w_attr: WindowAttributes, pl_attr: PlatformSpecificWindowBuilderAttributes, ) -> Result { @@ -728,7 +727,7 @@ impl Window { #[inline] pub fn get_current_monitor(&self) -> RootMonitorId { RootMonitorId { - inner: EventsLoop::get_current_monitor(self.window.0), + inner: EventLoop::get_current_monitor(self.window.0), } } @@ -807,7 +806,7 @@ unsafe fn init( mut attributes: WindowAttributes, mut pl_attribs: PlatformSpecificWindowBuilderAttributes, inserter: events_loop::Inserter, - events_loop_proxy: events_loop::EventsLoopProxy, + events_loop_proxy: events_loop::EventLoopProxy, ) -> Result { let title = OsStr::new(&attributes.title) .encode_wide() diff --git a/src/window.rs b/src/window.rs index cf36044880..604fc9fe60 100644 --- a/src/window.rs +++ b/src/window.rs @@ -2,7 +2,7 @@ use std::collections::vec_deque::IntoIter as VecDequeIter; use { CreationError, - EventsLoop, + EventLoop, Icon, LogicalPosition, LogicalSize, @@ -142,7 +142,7 @@ impl WindowBuilder { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn build(mut self, events_loop: &EventsLoop) -> Result { + pub fn build(mut self, events_loop: &EventLoop) -> Result { self.window.dimensions = Some(self.window.dimensions.unwrap_or_else(|| { if let Some(ref monitor) = self.window.fullscreen { // resizing the window to the dimensions of the monitor when fullscreen @@ -170,7 +170,7 @@ impl Window { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn new(events_loop: &EventsLoop) -> Result { + pub fn new(events_loop: &EventLoop) -> Result { let builder = WindowBuilder::new(); builder.build(events_loop) } @@ -408,7 +408,7 @@ impl Window { /// Returns the list of all the monitors available on the system. /// - /// This is the same as `EventsLoop::get_available_monitors`, and is provided for convenience. + /// This is the same as `EventLoop::get_available_monitors`, and is provided for convenience. #[inline] pub fn get_available_monitors(&self) -> AvailableMonitorsIter { let data = self.window.get_available_monitors(); @@ -417,7 +417,7 @@ impl Window { /// Returns the primary monitor of the system. /// - /// This is the same as `EventsLoop::get_primary_monitor`, and is provided for convenience. + /// This is the same as `EventLoop::get_primary_monitor`, and is provided for convenience. #[inline] pub fn get_primary_monitor(&self) -> MonitorId { MonitorId { inner: self.window.get_primary_monitor() } diff --git a/tests/send_objects.rs b/tests/send_objects.rs index f3328c100d..d0a34fd024 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -4,8 +4,8 @@ fn needs_send() {} #[test] fn events_loop_proxy_send() { - // ensures that `winit::EventsLoopProxy` implements `Send` - needs_send::(); + // ensures that `winit::EventLoopProxy` implements `Send` + needs_send::(); } #[test] From 64b8a9c6a50362d10c074077a1e37b057f3e3c81 Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 12 Jul 2018 22:13:07 -0400 Subject: [PATCH 02/40] Rename WindowEvent::Refresh to WindowEvent::Redraw --- src/events.rs | 2 +- src/platform/android/mod.rs | 2 +- src/platform/linux/wayland/event_loop.rs | 2 +- src/platform/linux/x11/mod.rs | 2 +- src/platform/windows/events_loop.rs | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/events.rs b/src/events.rs index 6725b19a0d..c740c29770 100644 --- a/src/events.rs +++ b/src/events.rs @@ -91,7 +91,7 @@ pub enum WindowEvent { AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 }, /// The window needs to be redrawn. - Refresh, + Redraw, /// Touch event has been received Touch(Touch), diff --git a/src/platform/android/mod.rs b/src/platform/android/mod.rs index 9b4f76a896..47a8d2ac20 100644 --- a/src/platform/android/mod.rs +++ b/src/platform/android/mod.rs @@ -116,7 +116,7 @@ impl EventLoop { // The activity needs to be redrawn. Some(Event::WindowEvent { window_id: RootWindowId(WindowId), - event: WindowEvent::Refresh, + event: WindowEvent::Redraw, }) } android_glue::Event::Wake => { diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index 50c8d2ebb7..f19713e968 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -264,7 +264,7 @@ impl EventLoop { sink.send_event(::WindowEvent::HiDpiFactorChanged(dpi as f64), wid); } if refresh { - sink.send_event(::WindowEvent::Refresh, wid); + sink.send_event(::WindowEvent::Redraw, wid); } if closed { sink.send_event(::WindowEvent::CloseRequested, wid); diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index c817aeadff..d1ff7a63c0 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -580,7 +580,7 @@ impl EventLoop { let window = xev.window; let window_id = mkwid(window); - callback(Event::WindowEvent { window_id, event: WindowEvent::Refresh }); + callback(Event::WindowEvent { window_id, event: WindowEvent::Redraw }); } ffi::KeyPress | ffi::KeyRelease => { diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index 9ccd394ddf..0fdce07f99 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -480,10 +480,10 @@ pub unsafe extern "system" fn callback( }, winuser::WM_PAINT => { - use events::WindowEvent::Refresh; + use events::WindowEvent::Redraw; send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), - event: Refresh, + event: Redraw, }); winuser::DefWindowProcW(window, msg, wparam, lparam) }, From 2e83bac99cc264cd2723cb182feea84a0a15e08d Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 12 Jul 2018 23:43:58 -0400 Subject: [PATCH 03/40] Remove second thread from win32 backend --- Cargo.toml | 1 + src/lib.rs | 9 - src/platform/windows/drop_handler.rs | 19 +- src/platform/windows/events_loop.rs | 610 +++++++++++---------------- src/platform/windows/window.rs | 68 ++- 5 files changed, 299 insertions(+), 408 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e06f5e862..3ae8aa2d75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ core-graphics = "0.17.3" version = "0.3.6" features = [ "combaseapi", + "commctrl", "dwmapi", "errhandlingapi", "hidusage", diff --git a/src/lib.rs b/src/lib.rs index 78874f2b45..9e60e78d66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -240,15 +240,6 @@ impl EventLoop { MonitorId { inner: self.events_loop.get_primary_monitor() } } - /// Fetches all the events that are pending, calls the callback function for each of them, - /// and returns. - #[inline] - pub fn poll_events(&mut self, callback: F) - where F: FnMut(Event) - { - self.events_loop.poll_events(callback) - } - /// Calls `callback` every time an event is received. If no event is available, sleeps the /// current thread and waits for an event. If the callback returns `ControlFlow::Break` then /// `run_forever` will immediately return. diff --git a/src/platform/windows/drop_handler.rs b/src/platform/windows/drop_handler.rs index e7bd12d026..d3f28a9b36 100644 --- a/src/platform/windows/drop_handler.rs +++ b/src/platform/windows/drop_handler.rs @@ -3,6 +3,8 @@ use std::os::windows::ffi::OsStringExt; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use std::{mem, ptr}; +use std::rc::Rc; +use std::cell::RefCell; use winapi::ctypes::c_void; use winapi::shared::guiddef::REFIID; @@ -14,7 +16,6 @@ use winapi::um::oleidl::{IDropTarget, IDropTargetVtbl}; use winapi::um::winnt::HRESULT; use winapi::um::{shellapi, unknwnbase}; -use platform::platform::events_loop::send_event; use platform::platform::WindowId; use {Event, WindowId as SuperWindowId}; @@ -24,6 +25,7 @@ pub struct FileDropHandlerData { pub interface: IDropTarget, refcount: AtomicUsize, window: HWND, + event_queue: Rc>>, } pub struct FileDropHandler { @@ -32,13 +34,14 @@ pub struct FileDropHandler { #[allow(non_snake_case)] impl FileDropHandler { - pub fn new(window: HWND) -> FileDropHandler { + pub fn new(window: HWND, event_queue: Rc>>) -> FileDropHandler { let data = Box::new(FileDropHandlerData { interface: IDropTarget { lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl, }, refcount: AtomicUsize::new(1), window, + event_queue, }); FileDropHandler { data: Box::into_raw(data), @@ -82,7 +85,7 @@ impl FileDropHandler { use events::WindowEvent::HoveredFile; let drop_handler = Self::from_interface(this); Self::iterate_filenames(pDataObj, |filename| { - send_event(Event::WindowEvent { + drop_handler.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(drop_handler.window)), event: HoveredFile(filename), }); @@ -103,7 +106,7 @@ impl FileDropHandler { pub unsafe extern "system" fn DragLeave(this: *mut IDropTarget) -> HRESULT { use events::WindowEvent::HoveredFileCancelled; let drop_handler = Self::from_interface(this); - send_event(Event::WindowEvent { + drop_handler.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(drop_handler.window)), event: HoveredFileCancelled, }); @@ -121,7 +124,7 @@ impl FileDropHandler { use events::WindowEvent::DroppedFile; let drop_handler = Self::from_interface(this); let hdrop = Self::iterate_filenames(pDataObj, |filename| { - send_event(Event::WindowEvent { + drop_handler.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(drop_handler.window)), event: DroppedFile(filename), }); @@ -182,6 +185,12 @@ impl FileDropHandler { } } +impl FileDropHandlerData { + fn send_event(&self, event: Event) { + self.event_queue.borrow_mut().push(event); + } +} + impl Drop for FileDropHandler { fn drop(&mut self) { unsafe { diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index 0fdce07f99..17d6c526b1 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -12,11 +12,14 @@ //! The closure passed to the `execute_in_thread` method takes an `Inserter` that you can use to //! add a `WindowState` entry to a list of window to be used by the callback. -use std::{mem, ptr, thread}; +use winapi::shared::basetsd::DWORD_PTR; +use winapi::shared::basetsd::UINT_PTR; +use std::rc::Rc; +use std::{mem, ptr}; use std::cell::RefCell; -use std::collections::HashMap; -use std::os::windows::io::AsRawHandle; -use std::sync::{Arc, Barrier, mpsc, Mutex}; +use std::ffi::OsString; +use std::os::windows::ffi::OsStringExt; +use std::sync::{Arc, Mutex}; use winapi::ctypes::c_int; use winapi::shared::minwindef::{ @@ -33,7 +36,7 @@ use winapi::shared::minwindef::{ use winapi::shared::windef::{HWND, POINT, RECT}; use winapi::shared::windowsx; use winapi::shared::winerror::S_OK; -use winapi::um::{winuser, processthreadsapi, ole2}; +use winapi::um::{winuser, processthreadsapi, ole2, shellapi, commctrl}; use winapi::um::oleidl::LPDROPTARGET; use winapi::um::winnt::{LONG, LPCSTR, SHORT}; @@ -102,6 +105,19 @@ pub struct WindowState { pub always_on_top: bool, pub maximized: bool, pub resizable: bool, + pub mouse_buttons_down: u32 +} + +pub(crate) struct SubclassInput { + pub window_state: Arc>, + pub event_queue: Rc>>, + pub file_drop_handler: FileDropHandler +} + +impl SubclassInput { + fn send_event(&self, event: Event) { + self.event_queue.borrow_mut().push(event); + } } impl WindowState { @@ -117,27 +133,10 @@ impl WindowState { } } -/// Dummy object that allows inserting a window's state. -// We store a pointer in order to !impl Send and Sync. -pub struct Inserter(*mut u8); - -impl Inserter { - /// Inserts a window's state for the callback to use. The state is removed automatically if the - /// callback receives a `WM_CLOSE` message for the window. - pub fn insert(&self, window: HWND, state: Arc>) { - CONTEXT_STASH.with(|context_stash| { - let mut context_stash = context_stash.borrow_mut(); - let was_in = context_stash.as_mut().unwrap().windows.insert(window, state); - assert!(was_in.is_none()); - }); - } -} - pub struct EventLoop { // Id of the background thread from the Win32 API. thread_id: DWORD, - // Receiver for the events. The sender is in the background thread. - receiver: mpsc::Receiver, + pub(crate) event_queue: Rc>> } impl EventLoop { @@ -148,101 +147,55 @@ impl EventLoop { pub fn with_dpi_awareness(dpi_aware: bool) -> EventLoop { become_dpi_aware(dpi_aware); - // The main events transfer channel. - let (tx, rx) = mpsc::channel(); - - // Local barrier in order to block the `new()` function until the background thread has - // an events queue. - let barrier = Arc::new(Barrier::new(2)); - let barrier_clone = barrier.clone(); - - let thread = thread::spawn(move || { - CONTEXT_STASH.with(|context_stash| { - *context_stash.borrow_mut() = Some(ThreadLocalData { - sender: tx, - windows: HashMap::with_capacity(4), - file_drop_handlers: HashMap::with_capacity(4), - mouse_buttons_down: 0, - }); - }); - - unsafe { - // Calling `PostThreadMessageA` on a thread that does not have an events queue yet - // will fail. In order to avoid this situation, we call `IsGuiThread` to initialize - // it. - winuser::IsGUIThread(1); - // Then only we unblock the `new()` function. We are sure that we don't call - // `PostThreadMessageA()` before `new()` returns. - barrier_clone.wait(); - drop(barrier_clone); - - let mut msg = mem::uninitialized(); - - loop { - if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 { - // Only happens if the message is `WM_QUIT`. - debug_assert_eq!(msg.message, winuser::WM_QUIT); - break; - } - - match msg.message { - x if x == *EXEC_MSG_ID => { - let mut function: Box> = Box::from_raw(msg.wParam as usize as *mut _); - function(Inserter(ptr::null_mut())); - }, - x if x == *WAKEUP_MSG_ID => { - send_event(Event::Awakened); - }, - _ => { - // Calls `callback` below. - winuser::TranslateMessage(&msg); - winuser::DispatchMessageW(&msg); - } - } - } - } - }); - - // Blocks this function until the background thread has an events loop. See other comments. - barrier.wait(); - - let thread_id = unsafe { - let handle = mem::transmute(thread.as_raw_handle()); - processthreadsapi::GetThreadId(handle) - }; + let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; EventLoop { thread_id, - receiver: rx, - } - } - - pub fn poll_events(&mut self, mut callback: F) - where F: FnMut(Event) - { - loop { - let event = match self.receiver.try_recv() { - Ok(e) => e, - Err(_) => return - }; - - callback(event); + event_queue: Rc::new(RefCell::new(Vec::new())) } } pub fn run_forever(&mut self, mut callback: F) where F: FnMut(Event) -> ControlFlow { - loop { - let event = match self.receiver.recv() { - Ok(e) => e, - Err(_) => return - }; + unsafe { + // Calling `PostThreadMessageA` on a thread that does not have an events queue yet + // will fail. In order to avoid this situation, we call `IsGuiThread` to initialize + // it. + winuser::IsGUIThread(1); + + let mut msg = mem::uninitialized(); + + loop { + if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 { + // Only happens if the message is `WM_QUIT`. + debug_assert_eq!(msg.message, winuser::WM_QUIT); + return; + } - let flow = callback(event); - match flow { - ControlFlow::Continue => continue, - ControlFlow::Break => break, + match msg.message { + x if x == *WAKEUP_MSG_ID => { + if ControlFlow::Break == callback(Event::Awakened) { + return; + } + }, + x if x == *EXEC_MSG_ID => { + let mut function: Box> = Box::from_raw(msg.wParam as usize as *mut _); + function() + } + _ => { + // Calls `callback` below. + winuser::TranslateMessage(&msg); + winuser::DispatchMessageW(&msg); + } + } + + let mut event_queue = self.event_queue.borrow_mut(); + for event in event_queue.drain(..) { + if ControlFlow::Break == callback(event) { + return; + } + } } } } @@ -252,19 +205,6 @@ impl EventLoop { thread_id: self.thread_id, } } - - /// Executes a function in the background thread. - /// - /// Note that we use a FnMut instead of a FnOnce because we're too lazy to create an equivalent - /// to the unstable FnBox. - /// - /// The `Inserted` can be used to inject a `WindowState` for the callback to use. The state is - /// removed automatically if the callback receives a `WM_CLOSE` message for the window. - pub(super) fn execute_in_thread(&self, function: F) - where F: FnMut(Inserter) + Send + 'static - { - self.create_proxy().execute_in_thread(function) - } } impl Drop for EventLoop { @@ -299,11 +239,14 @@ impl EventLoopProxy { } } - /// Executes a function in the background thread. - /// - /// Note that we use FnMut instead of FnOnce because boxing FnOnce won't work on stable Rust - /// until 2030 when the design of Box is finally complete. - /// https://github.com/rust-lang/rust/issues/28796 + /// Check to see if we're in the parent event loop's thread. + pub(super) fn in_event_loop_thread(&self) -> bool { + let cur_thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; + self.thread_id == cur_thread_id + } + + /// Executes a function in the event loop thread. If we're already in the event loop thread, + /// we just call the function directly. /// /// The `Inserted` can be used to inject a `WindowState` for the callback to use. The state is /// removed automatically if the callback receives a `WM_CLOSE` message for the window. @@ -312,25 +255,29 @@ impl EventLoopProxy { /// `WindowState` then you should call this within the lock of `WindowState`. Otherwise the /// events may be sent to the other thread in different order to the one in which you set /// `WindowState`, leaving them out of sync. - pub fn execute_in_thread(&self, function: F) - where - F: FnMut(Inserter) + Send + 'static, + /// + /// Note that we use a FnMut instead of a FnOnce because we're too lazy to create an equivalent + /// to the unstable FnBox. + pub(super) fn execute_in_thread(&self, mut function: F) + where F: FnMut() + Send + 'static { - // We are using double-boxing here because it make casting back much easier - let double_box = Box::new(Box::new(function) as Box); - let raw = Box::into_raw(double_box); - - let res = unsafe { - winuser::PostThreadMessageA( - self.thread_id, - *EXEC_MSG_ID, - raw as *mut () as usize as WPARAM, - 0, - ) - }; - // PostThreadMessage can only fail if the thread ID is invalid (which shouldn't happen as - // the events loop is still alive) or if the queue is full. - assert!(res != 0, "PostThreadMessage failed; is the messages queue full?"); + unsafe { + if self.in_event_loop_thread() { + function(); + } else { + // We double-box because the first box is a fat pointer. + let boxed = Box::new(function) as Box; + let boxed2 = Box::new(boxed); + + let raw = Box::into_raw(boxed2); + + let res = winuser::PostThreadMessageA(self.thread_id, *EXEC_MSG_ID, + raw as *mut () as usize as WPARAM, 0); + // PostThreadMessage can only fail if the thread ID is invalid (which shouldn't happen + // as the events loop is still alive) or if the queue is full. + assert!(res != 0, "PostThreadMessage failed ; is the messages queue full?"); + } + } } } @@ -347,7 +294,7 @@ lazy_static! { // and LPARAM is unused. static ref EXEC_MSG_ID: u32 = { unsafe { - winuser::RegisterWindowMessageA("Winit::ExecMsg\0".as_ptr() as LPCSTR) + winuser::RegisterWindowMessageA("Winit::ExecMsg\0".as_ptr() as *const i8) } }; // Message sent by a `Window` when it wants to be destroyed by the main thread. @@ -366,49 +313,32 @@ lazy_static! { }; } -// There's no parameters passed to the callback function, so it needs to get its context stashed -// in a thread-local variable. -thread_local!(static CONTEXT_STASH: RefCell> = RefCell::new(None)); -struct ThreadLocalData { - sender: mpsc::Sender, - windows: HashMap>>, - file_drop_handlers: HashMap, // Each window has its own drop handler. - mouse_buttons_down: u32, -} - -// Utility function that dispatches an event on the current thread. -pub fn send_event(event: Event) { - CONTEXT_STASH.with(|context_stash| { - let context_stash = context_stash.borrow(); - - let _ = context_stash.as_ref().unwrap().sender.send(event); // Ignoring if closed - }); -} - /// Capture mouse input, allowing `window` to receive mouse events when the cursor is outside of /// the window. -unsafe fn capture_mouse(window: HWND) { - CONTEXT_STASH.with(|context_stash| { - let mut context_stash = context_stash.borrow_mut(); - if let Some(context_stash) = context_stash.as_mut() { - context_stash.mouse_buttons_down += 1; - winuser::SetCapture(window); - } - }); +unsafe fn capture_mouse(window: HWND, window_state: &mut WindowState) { + window_state.mouse_buttons_down += 1; + winuser::SetCapture(window); } /// Release mouse input, stopping windows on this thread from receiving mouse input when the cursor /// is outside the window. -unsafe fn release_mouse() { - CONTEXT_STASH.with(|context_stash| { - let mut context_stash = context_stash.borrow_mut(); - if let Some(context_stash) = context_stash.as_mut() { - context_stash.mouse_buttons_down = context_stash.mouse_buttons_down.saturating_sub(1); - if context_stash.mouse_buttons_down == 0 { - winuser::ReleaseCapture(); - } - } - }); +unsafe fn release_mouse(window_state: &mut WindowState) { + window_state.mouse_buttons_down = window_state.mouse_buttons_down.saturating_sub(1); + if window_state.mouse_buttons_down == 0 { + winuser::ReleaseCapture(); + } +} + +const WINDOW_SUBCLASS_ID: UINT_PTR = 0; +pub(crate) fn subclass_window(window: HWND, subclass_input: SubclassInput) { + let input_ptr = Box::into_raw(Box::new(subclass_input)); + let subclass_result = unsafe{ commctrl::SetWindowSubclass( + window, + Some(callback), + WINDOW_SUBCLASS_ID, + input_ptr as DWORD_PTR + ) }; + assert_eq!(subclass_result, 1); } /// Any window whose callback is configured to this function will have its events propagated @@ -423,40 +353,20 @@ pub unsafe extern "system" fn callback( msg: UINT, wparam: WPARAM, lparam: LPARAM, + _: UINT_PTR, + subclass_input_ptr: DWORD_PTR ) -> LRESULT { - match msg { - winuser::WM_CREATE => { - use winapi::shared::winerror::{OLE_E_WRONGCOMPOBJ, RPC_E_CHANGED_MODE}; - let ole_init_result = ole2::OleInitialize(ptr::null_mut()); - // It is ok if the initialize result is `S_FALSE` because it might happen that - // multiple windows are created on the same thread. - if ole_init_result == OLE_E_WRONGCOMPOBJ { - panic!("OleInitialize failed! Result was: `OLE_E_WRONGCOMPOBJ`"); - } else if ole_init_result == RPC_E_CHANGED_MODE { - panic!("OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`"); - } - - CONTEXT_STASH.with(|context_stash| { - let mut context_stash = context_stash.borrow_mut(); - - let drop_handlers = &mut context_stash.as_mut().unwrap().file_drop_handlers; - let new_handler = FileDropHandler::new(window); - let handler_interface_ptr = &mut (*new_handler.data).interface as LPDROPTARGET; - drop_handlers.insert(window, new_handler); - - assert_eq!(ole2::RegisterDragDrop(window, handler_interface_ptr), S_OK); - }); - 0 - }, + let subclass_input = &mut*(subclass_input_ptr as *mut SubclassInput); + match msg { winuser::WM_NCCREATE => { enable_non_client_dpi_scaling(window); - winuser::DefWindowProcW(window, msg, wparam, lparam) + commctrl::DefSubclassProc(window, msg, wparam, lparam) }, winuser::WM_CLOSE => { use events::WindowEvent::CloseRequested; - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: CloseRequested }); @@ -465,27 +375,24 @@ pub unsafe extern "system" fn callback( winuser::WM_DESTROY => { use events::WindowEvent::Destroyed; - CONTEXT_STASH.with(|context_stash| { - let mut context_stash = context_stash.borrow_mut(); - ole2::RevokeDragDrop(window); - let context_stash_mut = context_stash.as_mut().unwrap(); - context_stash_mut.file_drop_handlers.remove(&window); - context_stash_mut.windows.remove(&window); - }); - send_event(Event::WindowEvent { + ole2::RevokeDragDrop(window); + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: Destroyed }); + + Box::from_raw(subclass_input); + drop(subclass_input); 0 }, winuser::WM_PAINT => { use events::WindowEvent::Redraw; - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: Redraw, }); - winuser::DefWindowProcW(window, msg, wparam, lparam) + commctrl::DefSubclassProc(window, msg, wparam, lparam) }, // WM_MOVE supplies client area positions, so we send Moved here instead. @@ -499,14 +406,14 @@ pub unsafe extern "system" fn callback( ((*windowpos).x, (*windowpos).y), dpi_factor, ); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: Moved(logical_position), }); } // This is necessary for us to still get sent WM_SIZE. - winuser::DefWindowProcW(window, msg, wparam, lparam) + commctrl::DefSubclassProc(window, msg, wparam, lparam) }, winuser::WM_SIZE => { @@ -514,21 +421,14 @@ pub unsafe extern "system" fn callback( let w = LOWORD(lparam as DWORD) as u32; let h = HIWORD(lparam as DWORD) as u32; - // Wait for the parent thread to process the resize event before returning from the - // callback. - CONTEXT_STASH.with(|context_stash| { - let mut context_stash = context_stash.borrow_mut(); - let cstash = context_stash.as_mut().unwrap(); - - let dpi_factor = get_hwnd_scale_factor(window); - let logical_size = LogicalSize::from_physical((w, h), dpi_factor); - let event = Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), - event: Resized(logical_size), - }; + let dpi_factor = get_hwnd_scale_factor(window); + let logical_size = LogicalSize::from_physical((w, h), dpi_factor); + let event = Event::WindowEvent { + window_id: SuperWindowId(WindowId(window)), + event: Resized(logical_size), + }; - cstash.sender.send(event).ok(); - }); + subclass_input.send_event(event); 0 }, @@ -536,7 +436,7 @@ pub unsafe extern "system" fn callback( use std::mem; use events::WindowEvent::ReceivedCharacter; let chr: char = mem::transmute(wparam as u32); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: ReceivedCharacter(chr), }); @@ -553,23 +453,18 @@ pub unsafe extern "system" fn callback( winuser::WM_MOUSEMOVE => { use events::WindowEvent::{CursorEntered, CursorMoved}; - let mouse_outside_window = CONTEXT_STASH.with(|context_stash| { - let mut context_stash = context_stash.borrow_mut(); - if let Some(context_stash) = context_stash.as_mut() { - if let Some(w) = context_stash.windows.get_mut(&window) { - let mut w = w.lock().unwrap(); - if !w.mouse_in_window { - w.mouse_in_window = true; - return true; - } - } + let mouse_outside_window = { + let mut window = subclass_input.window_state.lock().unwrap(); + if !window.mouse_in_window { + window.mouse_in_window = true; + true + } else { + false } - - false - }); + }; if mouse_outside_window { - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: CursorEntered { device_id: DEVICE_ID }, }); @@ -588,7 +483,7 @@ pub unsafe extern "system" fn callback( let dpi_factor = get_hwnd_scale_factor(window); let position = LogicalPosition::from_physical((x, y), dpi_factor); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() }, }); @@ -598,23 +493,18 @@ pub unsafe extern "system" fn callback( winuser::WM_MOUSELEAVE => { use events::WindowEvent::CursorLeft; - let mouse_in_window = CONTEXT_STASH.with(|context_stash| { - let mut context_stash = context_stash.borrow_mut(); - if let Some(context_stash) = context_stash.as_mut() { - if let Some(w) = context_stash.windows.get_mut(&window) { - let mut w = w.lock().unwrap(); - if w.mouse_in_window { - w.mouse_in_window = false; - return true; - } - } + let mouse_in_window = { + let mut window = subclass_input.window_state.lock().unwrap(); + if window.mouse_in_window { + window.mouse_in_window = false; + true + } else { + false } - - false - }); + }; if mouse_in_window { - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: CursorLeft { device_id: DEVICE_ID } }); @@ -631,7 +521,7 @@ pub unsafe extern "system" fn callback( let value = value as i32; let value = value as f32 / winuser::WHEEL_DELTA as f32; - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved, modifiers: event::get_key_mods() }, }); @@ -643,10 +533,10 @@ pub unsafe extern "system" fn callback( use events::ElementState::Pressed; use events::VirtualKeyCode; if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 { - winuser::DefWindowProcW(window, msg, wparam, lparam) + commctrl::DefSubclassProc(window, msg, wparam, lparam) } else { if let Some((scancode, vkey)) = process_key_params(wparam, lparam) { - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: WindowEvent::KeyboardInput { device_id: DEVICE_ID, @@ -661,7 +551,7 @@ pub unsafe extern "system" fn callback( // Windows doesn't emit a delete character by default, but in order to make it // consistent with the other platforms we'll emit a delete character here. if vkey == Some(VirtualKeyCode::Delete) { - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: WindowEvent::ReceivedCharacter('\u{7F}'), }); @@ -674,7 +564,7 @@ pub unsafe extern "system" fn callback( winuser::WM_KEYUP | winuser::WM_SYSKEYUP => { use events::ElementState::Released; if let Some((scancode, vkey)) = process_key_params(wparam, lparam) { - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: WindowEvent::KeyboardInput { device_id: DEVICE_ID, @@ -695,9 +585,9 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Left; use events::ElementState::Pressed; - capture_mouse(window); + capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap()); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() } }); @@ -709,9 +599,9 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Left; use events::ElementState::Released; - release_mouse(); + release_mouse(&mut *subclass_input.window_state.lock().unwrap()); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() } }); @@ -723,9 +613,9 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Right; use events::ElementState::Pressed; - capture_mouse(window); + capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap()); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() } }); @@ -737,9 +627,9 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Right; use events::ElementState::Released; - release_mouse(); + release_mouse(&mut *subclass_input.window_state.lock().unwrap()); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() } }); @@ -751,9 +641,9 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Middle; use events::ElementState::Pressed; - capture_mouse(window); + capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap()); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() } }); @@ -765,9 +655,9 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Middle; use events::ElementState::Released; - release_mouse(); + release_mouse(&mut *subclass_input.window_state.lock().unwrap()); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() } }); @@ -780,9 +670,9 @@ pub unsafe extern "system" fn callback( use events::ElementState::Pressed; let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); - capture_mouse(window); + capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap()); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() } }); @@ -795,9 +685,9 @@ pub unsafe extern "system" fn callback( use events::ElementState::Released; let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); - release_mouse(); + release_mouse(&mut *subclass_input.window_state.lock().unwrap()); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() } }); @@ -811,12 +701,12 @@ pub unsafe extern "system" fn callback( _ => unreachable!(), }; - send_event(Event::DeviceEvent { + subclass_input.send_event(Event::DeviceEvent { device_id: wrap_device_id(lparam as _), event, }); - winuser::DefWindowProcW(window, msg, wparam, lparam) + commctrl::DefSubclassProc(window, msg, wparam, lparam) }, winuser::WM_INPUT => { @@ -835,21 +725,21 @@ pub unsafe extern "system" fn callback( let y = mouse.lLastY as f64; if x != 0.0 { - send_event(Event::DeviceEvent { + subclass_input.send_event(Event::DeviceEvent { device_id, event: Motion { axis: 0, value: x } }); } if y != 0.0 { - send_event(Event::DeviceEvent { + subclass_input.send_event(Event::DeviceEvent { device_id, event: Motion { axis: 1, value: y } }); } if x != 0.0 || y != 0.0 { - send_event(Event::DeviceEvent { + subclass_input.send_event(Event::DeviceEvent { device_id, event: MouseMotion { delta: (x, y) } }); @@ -858,7 +748,7 @@ pub unsafe extern "system" fn callback( if util::has_flag(mouse.usButtonFlags, winuser::RI_MOUSE_WHEEL) { let delta = mouse.usButtonData as SHORT / winuser::WHEEL_DELTA; - send_event(Event::DeviceEvent { + subclass_input.send_event(Event::DeviceEvent { device_id, event: MouseWheel { delta: LineDelta(0.0, delta as f32) } }); @@ -872,7 +762,7 @@ pub unsafe extern "system" fn callback( // seem to be anything else reasonable to do for a mouse // button ID. let button = (index + 1) as _; - send_event(Event::DeviceEvent { + subclass_input.send_event(Event::DeviceEvent { device_id, event: Button { button, @@ -906,7 +796,7 @@ pub unsafe extern "system" fn callback( ) { let virtual_keycode = vkey_to_winit_vkey(vkey); - send_event(Event::DeviceEvent { + subclass_input.send_event(Event::DeviceEvent { device_id, event: Key(KeyboardInput { scancode, @@ -920,7 +810,7 @@ pub unsafe extern "system" fn callback( } } - winuser::DefWindowProcW(window, msg, wparam, lparam) + commctrl::DefSubclassProc(window, msg, wparam, lparam) }, winuser::WM_TOUCH => { @@ -939,7 +829,7 @@ pub unsafe extern "system" fn callback( let x = (input.x as f64) / 100f64; let y = (input.y as f64) / 100f64; let location = LogicalPosition::from_physical((x, y), dpi_factor); - send_event( Event::WindowEvent { + subclass_input.send_event( Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: WindowEvent::Touch(Touch { phase: @@ -965,7 +855,7 @@ pub unsafe extern "system" fn callback( winuser::WM_SETFOCUS => { use events::WindowEvent::{Focused, CursorMoved}; - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: Focused(true) }); @@ -975,7 +865,7 @@ pub unsafe extern "system" fn callback( let dpi_factor = get_hwnd_scale_factor(window); let position = LogicalPosition::from_physical((x, y), dpi_factor); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() }, }); @@ -985,7 +875,7 @@ pub unsafe extern "system" fn callback( winuser::WM_KILLFOCUS => { use events::WindowEvent::Focused; - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: Focused(false) }); @@ -993,29 +883,22 @@ pub unsafe extern "system" fn callback( }, winuser::WM_SETCURSOR => { - let call_def_window_proc = CONTEXT_STASH.with(|context_stash| { - context_stash - .borrow() - .as_ref() - .and_then(|cstash| cstash.windows.get(&window)) - .map(|window_state_mutex| { - let window_state = window_state_mutex.lock().unwrap(); - if window_state.mouse_in_window { - let cursor = winuser::LoadCursorW( - ptr::null_mut(), - window_state.cursor.0, - ); - winuser::SetCursor(cursor); - false - } else { - true - } - }) - .unwrap_or(true) - }); + let call_def_window_proc = { + let window_state = subclass_input.window_state.lock().unwrap(); + if window_state.mouse_in_window { + let cursor = winuser::LoadCursorW( + ptr::null_mut(), + window_state.cursor.0, + ); + winuser::SetCursor(cursor); + false + } else { + true + } + }; if call_def_window_proc { - winuser::DefWindowProcW(window, msg, wparam, lparam) + commctrl::DefSubclassProc(window, msg, wparam, lparam) } else { 0 } @@ -1028,29 +911,21 @@ pub unsafe extern "system" fn callback( winuser::WM_GETMINMAXINFO => { let mmi = lparam as *mut winuser::MINMAXINFO; - //(*mmi).max_position = winapi::shared::windef::POINT { x: -8, y: -8 }; // The upper left corner of the window if it were maximized on the primary monitor. - //(*mmi).max_size = winapi::shared::windef::POINT { x: .., y: .. }; // The dimensions of the primary monitor. - - CONTEXT_STASH.with(|context_stash| { - if let Some(cstash) = context_stash.borrow().as_ref() { - if let Some(wstash) = cstash.windows.get(&window) { - let window_state = wstash.lock().unwrap(); - - if window_state.min_size.is_some() || window_state.max_size.is_some() { - let style = winuser::GetWindowLongA(window, winuser::GWL_STYLE) as DWORD; - let ex_style = winuser::GetWindowLongA(window, winuser::GWL_EXSTYLE) as DWORD; - if let Some(min_size) = window_state.min_size { - let (width, height) = adjust_size(min_size, style, ex_style); - (*mmi).ptMinTrackSize = POINT { x: width as i32, y: height as i32 }; - } - if let Some(max_size) = window_state.max_size { - let (width, height) = adjust_size(max_size, style, ex_style); - (*mmi).ptMaxTrackSize = POINT { x: width as i32, y: height as i32 }; - } - } - } + + let window_state = subclass_input.window_state.lock().unwrap(); + + if window_state.min_size.is_some() || window_state.max_size.is_some() { + let style = winuser::GetWindowLongA(window, winuser::GWL_STYLE) as DWORD; + let ex_style = winuser::GetWindowLongA(window, winuser::GWL_EXSTYLE) as DWORD; + if let Some(min_size) = window_state.min_size { + let (width, height) = adjust_size(min_size, style, ex_style); + (*mmi).ptMinTrackSize = POINT { x: width as i32, y: height as i32 }; } - }); + if let Some(max_size) = window_state.max_size { + let (width, height) = adjust_size(max_size, style, ex_style); + (*mmi).ptMaxTrackSize = POINT { x: width as i32, y: height as i32 }; + } + } 0 }, @@ -1067,34 +942,27 @@ pub unsafe extern "system" fn callback( let new_dpi_x = u32::from(LOWORD(wparam as DWORD)); let new_dpi_factor = dpi_to_scale_factor(new_dpi_x); - let suppress_resize = CONTEXT_STASH.with(|context_stash| { - context_stash - .borrow() - .as_ref() - .and_then(|cstash| cstash.windows.get(&window)) - .map(|window_state_mutex| { - let mut window_state = window_state_mutex.lock().unwrap(); - let suppress_resize = window_state.saved_window_info - .as_mut() - .map(|saved_window_info| { - let dpi_changed = if !saved_window_info.is_fullscreen { - saved_window_info.dpi_factor.take() != Some(new_dpi_factor) - } else { - false - }; - !dpi_changed || saved_window_info.is_fullscreen - }) - .unwrap_or(false); - // Now we adjust the min/max dimensions for the new DPI. - if !suppress_resize { - let old_dpi_factor = window_state.dpi_factor; - window_state.update_min_max(old_dpi_factor, new_dpi_factor); - } - window_state.dpi_factor = new_dpi_factor; - suppress_resize + let suppress_resize = { + let mut window_state = subclass_input.window_state.lock().unwrap(); + let suppress_resize = window_state.saved_window_info + .as_mut() + .map(|saved_window_info| { + let dpi_changed = if !saved_window_info.is_fullscreen { + saved_window_info.dpi_factor.take() != Some(new_dpi_factor) + } else { + false + }; + !dpi_changed || saved_window_info.is_fullscreen }) - .unwrap_or(false) - }); + .unwrap_or(false); + // Now we adjust the min/max dimensions for the new DPI. + if !suppress_resize { + let old_dpi_factor = window_state.dpi_factor; + window_state.update_min_max(old_dpi_factor, new_dpi_factor); + } + window_state.dpi_factor = new_dpi_factor; + suppress_resize + }; // This prevents us from re-applying DPI adjustment to the restored size after exiting // fullscreen (the restored size is already DPI adjusted). @@ -1112,7 +980,7 @@ pub unsafe extern "system" fn callback( ); } - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: HiDpiFactorChanged(new_dpi_factor), }); @@ -1127,7 +995,7 @@ pub unsafe extern "system" fn callback( } else if msg == *INITIAL_DPI_MSG_ID { use events::WindowEvent::HiDpiFactorChanged; let scale_factor = dpi_to_scale_factor(wparam as u32); - send_event(Event::WindowEvent { + subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: HiDpiFactorChanged(scale_factor), }); @@ -1165,7 +1033,7 @@ pub unsafe extern "system" fn callback( ); 0 } else { - winuser::DefWindowProcW(window, msg, wparam, lparam) + commctrl::DefSubclassProc(window, msg, wparam, lparam) } } } diff --git a/src/platform/windows/window.rs b/src/platform/windows/window.rs index 95c821e7a7..899e461077 100644 --- a/src/platform/windows/window.rs +++ b/src/platform/windows/window.rs @@ -10,10 +10,11 @@ use std::sync::mpsc::channel; use winapi::ctypes::c_int; use winapi::shared::minwindef::{BOOL, DWORD, FALSE, LPARAM, TRUE, UINT, WORD, WPARAM}; use winapi::shared::windef::{HWND, LPPOINT, POINT, RECT}; -use winapi::um::{combaseapi, dwmapi, libloaderapi, winuser}; +use winapi::um::{combaseapi, dwmapi, libloaderapi, winuser, ole2}; use winapi::um::objbase::COINIT_MULTITHREADED; use winapi::um::shobjidl_core::{CLSID_TaskbarList, ITaskbarList2}; use winapi::um::wingdi::{CreateRectRgn, DeleteObject}; +use winapi::um::oleidl::LPDROPTARGET; use winapi::um::winnt::{LONG, LPCWSTR}; use { @@ -32,6 +33,7 @@ use platform::platform::events_loop::{self, DESTROY_MSG_ID, EventLoop, INITIAL_D use platform::platform::icon::{self, IconType, WinIcon}; use platform::platform::monitor::get_available_monitors; use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input; +use platform::platform::drop_handler::FileDropHandler; use platform::platform::util; const WS_RESIZABLE: DWORD = winuser::WS_SIZEBOX | winuser::WS_MAXIMIZEBOX; @@ -76,15 +78,11 @@ impl Window { w_attr: WindowAttributes, pl_attr: PlatformSpecificWindowBuilderAttributes, ) -> Result { - let (tx, rx) = channel(); - let proxy = events_loop.create_proxy(); - events_loop.execute_in_thread(move |inserter| { - // We dispatch an `init` function because of code style. - // First person to remove the need for cloning here gets a cookie! - let win = unsafe { init(w_attr.clone(), pl_attr.clone(), inserter, proxy.clone()) }; - let _ = tx.send(win); - }); - rx.recv().unwrap() + // We dispatch an `init` function because of code style. + // First person to remove the need for cloning here gets a cookie! + // + // done. you owe me -- ossi + unsafe { init(w_attr, pl_attr, events_loop) } } pub fn set_title(&self, text: &str) { @@ -323,7 +321,7 @@ impl Window { _ => winuser::IDC_ARROW, // use arrow for the missing cases. }); self.window_state.lock().unwrap().cursor = cursor_id; - self.events_loop_proxy.execute_in_thread(move |_| unsafe { + self.events_loop_proxy.execute_in_thread(move || unsafe { let cursor = winuser::LoadCursorW( ptr::null_mut(), cursor_id.0, @@ -385,7 +383,7 @@ impl Window { let window = self.window.clone(); let window_state = Arc::clone(&self.window_state); let (tx, rx) = channel(); - self.events_loop_proxy.execute_in_thread(move |_| { + self.events_loop_proxy.execute_in_thread(move || { let result = unsafe { Self::grab_cursor_inner(&window, grab) }; if result.is_ok() { window_state.lock().unwrap().cursor_grabbed = grab; @@ -411,7 +409,7 @@ impl Window { if hide == window_state_lock.cursor_hidden { return; } let (tx, rx) = channel(); let window_state = Arc::clone(&self.window_state); - self.events_loop_proxy.execute_in_thread(move |_| { + self.events_loop_proxy.execute_in_thread(move || { unsafe { Self::hide_cursor_inner(hide) }; window_state.lock().unwrap().cursor_hidden = hide; let _ = tx.send(()); @@ -459,7 +457,7 @@ impl Window { let window = self.window.clone(); unsafe { // `ShowWindow` resizes the window, so it must be called from the main thread. - self.events_loop_proxy.execute_in_thread(move |_| { + self.events_loop_proxy.execute_in_thread(move || { winuser::ShowWindow( window.0, if maximized { @@ -524,7 +522,7 @@ impl Window { // We're restoring the window to its size and position from before being fullscreened. // `ShowWindow` resizes the window, so it must be called from the main thread. - self.events_loop_proxy.execute_in_thread(move |_| { + self.events_loop_proxy.execute_in_thread(move || { let _ = Self::grab_cursor_inner(&window, false); if resizable { @@ -577,7 +575,7 @@ impl Window { let window_state = Arc::clone(&self.window_state); let (style, ex_style) = self.set_fullscreen_style(&mut window_state_lock); - self.events_loop_proxy.execute_in_thread(move |_| { + self.events_loop_proxy.execute_in_thread(move || { let _ = Self::grab_cursor_inner(&window, false); winuser::SetWindowLongW( @@ -674,7 +672,7 @@ impl Window { let window = self.window.clone(); - self.events_loop_proxy.execute_in_thread(move |_| { + self.events_loop_proxy.execute_in_thread(move || { winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style); winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style); winuser::AdjustWindowRectEx(&mut rect, style as _, 0, ex_style as _); @@ -702,7 +700,7 @@ impl Window { let mut window_state = self.window_state.lock().unwrap(); if mem::replace(&mut window_state.always_on_top, always_on_top) != always_on_top { let window = self.window.clone(); - self.events_loop_proxy.execute_in_thread(move |_| { + self.events_loop_proxy.execute_in_thread(move || { let insert_after = if always_on_top { winuser::HWND_TOPMOST } else { @@ -805,8 +803,7 @@ pub unsafe fn adjust_size( unsafe fn init( mut attributes: WindowAttributes, mut pl_attribs: PlatformSpecificWindowBuilderAttributes, - inserter: events_loop::Inserter, - events_loop_proxy: events_loop::EventLoopProxy, + event_loop: &events_loop::EventLoop, ) -> Result { let title = OsStr::new(&attributes.title) .encode_wide() @@ -1013,6 +1010,7 @@ unsafe fn init( maximized: attributes.maximized, resizable: attributes.resizable, always_on_top: attributes.always_on_top, + mouse_buttons_down: 0 }; // Creating a mutex to track the current window state Arc::new(Mutex::new(window_state)) @@ -1048,7 +1046,7 @@ unsafe fn init( let win = Window { window: real_window, window_state, - events_loop_proxy, + events_loop_proxy: event_loop.create_proxy(), }; win.set_maximized(attributes.maximized); @@ -1057,7 +1055,31 @@ unsafe fn init( force_window_active(win.window.0); } - inserter.insert(win.window.0, win.window_state.clone()); + let file_drop_handler = { + use winapi::shared::winerror::{OLE_E_WRONGCOMPOBJ, RPC_E_CHANGED_MODE, S_OK}; + let ole_init_result = ole2::OleInitialize(ptr::null_mut()); + // It is ok if the initialize result is `S_FALSE` because it might happen that + // multiple windows are created on the same thread. + if ole_init_result == OLE_E_WRONGCOMPOBJ { + panic!("OleInitialize failed! Result was: `OLE_E_WRONGCOMPOBJ`"); + } else if ole_init_result == RPC_E_CHANGED_MODE { + panic!("OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`"); + } + + let file_drop_handler = FileDropHandler::new(win.window.0, event_loop.event_queue.clone()); + let handler_interface_ptr = &mut (*file_drop_handler.data).interface as LPDROPTARGET; + + assert_eq!(ole2::RegisterDragDrop(win.window.0, handler_interface_ptr), S_OK); + file_drop_handler + }; + + let subclass_input = events_loop::SubclassInput { + window_state: win.window_state.clone(), + event_queue: event_loop.event_queue.clone(), + file_drop_handler + }; + + events_loop::subclass_window(win.window.0, subclass_input); Ok(win) } @@ -1083,7 +1105,7 @@ unsafe fn register_window_class( let class = winuser::WNDCLASSEXW { cbSize: mem::size_of::() as UINT, style: winuser::CS_HREDRAW | winuser::CS_VREDRAW | winuser::CS_OWNDC, - lpfnWndProc: Some(events_loop::callback), + lpfnWndProc: Some(winuser::DefWindowProcW), cbClsExtra: 0, cbWndExtra: 0, hInstance: libloaderapi::GetModuleHandleW(ptr::null()), From 9feada206f6b9fb1e9da118be6b77dfc217ace8d Mon Sep 17 00:00:00 2001 From: Osspial Date: Fri, 13 Jul 2018 01:39:53 -0400 Subject: [PATCH 04/40] Update run_forever to hijack thread --- examples/cursor.rs | 28 +++++++++++---- examples/cursor_grab.rs | 2 +- examples/fullscreen.rs | 2 +- examples/handling_close.rs | 2 +- examples/min_max_size.rs | 2 +- examples/multiwindow.rs | 26 ++++++++------ examples/proxy.rs | 2 +- examples/resizable.rs | 2 +- examples/transparent.rs | 2 +- examples/window.rs | 4 +-- examples/window_icon.rs | 2 +- src/lib.rs | 32 ++++++++++------- src/platform/windows/drop_handler.rs | 7 ++-- src/platform/windows/events_loop.rs | 51 ++++++++++++++++------------ 14 files changed, 100 insertions(+), 64 deletions(-) diff --git a/examples/cursor.rs b/examples/cursor.rs index 2eb5e8cbad..9feeb76c10 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -1,22 +1,21 @@ extern crate winit; -use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow}; +use winit::{Event, EventLoop, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow}; fn main() { - let mut events_loop = winit::EventLoop::new(); + let mut events_loop = EventLoop::new(); let window = winit::WindowBuilder::new().build(&events_loop).unwrap(); window.set_title("A fantastic window!"); - let cursors = [MouseCursor::Default, MouseCursor::Crosshair, MouseCursor::Hand, MouseCursor::Arrow, MouseCursor::Move, MouseCursor::Text, MouseCursor::Wait, MouseCursor::Help, MouseCursor::Progress, MouseCursor::NotAllowed, MouseCursor::ContextMenu, MouseCursor::Cell, MouseCursor::VerticalText, MouseCursor::Alias, MouseCursor::Copy, MouseCursor::NoDrop, MouseCursor::Grab, MouseCursor::Grabbing, MouseCursor::AllScroll, MouseCursor::ZoomIn, MouseCursor::ZoomOut, MouseCursor::EResize, MouseCursor::NResize, MouseCursor::NeResize, MouseCursor::NwResize, MouseCursor::SResize, MouseCursor::SeResize, MouseCursor::SwResize, MouseCursor::WResize, MouseCursor::EwResize, MouseCursor::NsResize, MouseCursor::NeswResize, MouseCursor::NwseResize, MouseCursor::ColResize, MouseCursor::RowResize]; let mut cursor_idx = 0; - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &EventLoop| { match event { Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => { - println!("Setting cursor to \"{:?}\"", cursors[cursor_idx]); - window.set_cursor(cursors[cursor_idx]); - if cursor_idx < cursors.len() - 1 { + println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]); + window.set_cursor(CURSORS[cursor_idx]); + if cursor_idx < CURSORS.len() - 1 { cursor_idx += 1; } else { cursor_idx = 0; @@ -30,3 +29,18 @@ fn main() { ControlFlow::Continue }); } + +const CURSORS: &[MouseCursor] = &[ + MouseCursor::Default, MouseCursor::Crosshair, MouseCursor::Hand, + MouseCursor::Arrow, MouseCursor::Move, MouseCursor::Text, + MouseCursor::Wait, MouseCursor::Help, MouseCursor::Progress, + MouseCursor::NotAllowed, MouseCursor::ContextMenu, MouseCursor::Cell, + MouseCursor::VerticalText, MouseCursor::Alias, MouseCursor::Copy, + MouseCursor::NoDrop, MouseCursor::Grab, MouseCursor::Grabbing, + MouseCursor::AllScroll, MouseCursor::ZoomIn, MouseCursor::ZoomOut, + MouseCursor::EResize, MouseCursor::NResize, MouseCursor::NeResize, + MouseCursor::NwResize, MouseCursor::SResize, MouseCursor::SeResize, + MouseCursor::SwResize, MouseCursor::WResize, MouseCursor::EwResize, + MouseCursor::NsResize, MouseCursor::NeswResize, MouseCursor::NwseResize, + MouseCursor::ColResize, MouseCursor::RowResize +]; diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index d36ef72a79..11456f73c1 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -8,7 +8,7 @@ fn main() { .build(&events_loop) .unwrap(); - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &winit::EventLoop| { if let winit::Event::WindowEvent { event, .. } = event { use winit::WindowEvent::*; match event { diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index c4cebca36a..84abb3518a 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -35,7 +35,7 @@ fn main() { let mut is_maximized = false; let mut decorations = true; - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &winit::EventLoop| { println!("{:?}", event); match event { diff --git a/examples/handling_close.rs b/examples/handling_close.rs index 3b4add4069..93d655bc65 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -10,7 +10,7 @@ fn main() { let mut close_requested = false; - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &winit::EventLoop| { use winit::WindowEvent::*; use winit::ElementState::Released; use winit::VirtualKeyCode::{N, Y}; diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index 836820e7fe..f011920bf7 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -12,7 +12,7 @@ fn main() { window.set_min_dimensions(Some(LogicalSize::new(400.0, 200.0))); window.set_max_dimensions(Some(LogicalSize::new(800.0, 400.0))); - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &winit::EventLoop| { println!("{:?}", event); match event { diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index 5b1d75a96f..3dfabf8922 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -11,19 +11,25 @@ fn main() { windows.insert(window.id(), window); } - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, events_loop: &winit::EventLoop| { match event { - winit::Event::WindowEvent { - event: winit::WindowEvent::CloseRequested, - window_id, - } => { - println!("Window {:?} has received the signal to close", window_id); + winit::Event::WindowEvent { event, window_id } => { + match event { + winit::WindowEvent::CloseRequested => { + println!("Window {:?} has received the signal to close", window_id); - // This drops the window, causing it to close. - windows.remove(&window_id); + // This drops the window, causing it to close. + windows.remove(&window_id); - if windows.is_empty() { - return winit::ControlFlow::Break; + if windows.is_empty() { + return winit::ControlFlow::Break; + } + }, + winit::WindowEvent::KeyboardInput{..} => { + let window = winit::Window::new(&events_loop).unwrap(); + windows.insert(window.id(), window); + }, + _ => () } } _ => (), diff --git a/examples/proxy.rs b/examples/proxy.rs index 8518c1e210..4df2efe4f9 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -18,7 +18,7 @@ fn main() { } }); - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &winit::EventLoop| { println!("{:?}", event); match event { winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => diff --git a/examples/resizable.rs b/examples/resizable.rs index fab1c65c8a..c84fe5b052 100644 --- a/examples/resizable.rs +++ b/examples/resizable.rs @@ -12,7 +12,7 @@ fn main() { .build(&events_loop) .unwrap(); - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &winit::EventLoop| { match event { winit::Event::WindowEvent { event, .. } => match event { winit::WindowEvent::CloseRequested => return winit::ControlFlow::Break, diff --git a/examples/transparent.rs b/examples/transparent.rs index c5be1f2330..7cfed50566 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -9,7 +9,7 @@ fn main() { window.set_title("A fantastic window!"); - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &winit::EventLoop| { println!("{:?}", event); match event { diff --git a/examples/window.rs b/examples/window.rs index 2b9803378b..e46386744f 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -1,14 +1,14 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); let _window = winit::WindowBuilder::new() .with_title("A fantastic window!") .build(&events_loop) .unwrap(); - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &winit::EventLoop| { println!("{:?}", event); match event { diff --git a/examples/window_icon.rs b/examples/window_icon.rs index 4cd9029c16..fc54c5394c 100644 --- a/examples/window_icon.rs +++ b/examples/window_icon.rs @@ -30,7 +30,7 @@ fn main() { .build(&events_loop) .unwrap(); - events_loop.run_forever(|event| { + events_loop.run_forever(move |event, _: &EventLoop| { if let winit::Event::WindowEvent { event, .. } = event { use winit::WindowEvent::*; match event { diff --git a/src/lib.rs b/src/lib.rs index 9e60e78d66..bdfdb9928a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ //! # use winit::EventLoop; //! # let mut events_loop = EventLoop::new(); //! -//! events_loop.run_forever(|event| { +//! events_loop.run_forever(move |event, _: &EventLoop| { //! match event { //! Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { //! println!("The close button was pressed; stopping"); @@ -139,7 +139,7 @@ pub mod os; /// let mut events_loop = EventLoop::new(); /// let window = Window::new(&events_loop).unwrap(); /// -/// events_loop.run_forever(|event| { +/// events_loop.run_forever(move |event, _: &EventLoop| { /// match event { /// Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { /// ControlFlow::Break @@ -199,6 +199,18 @@ impl std::fmt::Debug for EventLoop { } } +pub trait EventHandler { + fn handle_event(&mut self, event: Event, event_loop: &EventLoop) -> ControlFlow; +} + +impl EventHandler for F + where F: FnMut(Event, &EventLoop) -> ControlFlow +{ + fn handle_event(&mut self, event: Event, event_loop: &EventLoop) -> ControlFlow { + self(event, event_loop) + } +} + /// Returned by the user callback given to the `EventLoop::run_forever` method. /// /// Indicates whether the `run_forever` method should continue or complete. @@ -240,19 +252,13 @@ impl EventLoop { MonitorId { inner: self.events_loop.get_primary_monitor() } } - /// Calls `callback` every time an event is received. If no event is available, sleeps the - /// current thread and waits for an event. If the callback returns `ControlFlow::Break` then - /// `run_forever` will immediately return. - /// - /// # Danger! + /// Hijacks the calling thread and initializes the `winit` event loop. Can take a + /// `FnMut(Event, &EventLoop) -> ControlFlow` or a custom `EventHandler` type. /// - /// The callback is run after *every* event, so if its execution time is non-trivial the event queue may not empty - /// at a sufficient rate. Rendering in the callback with vsync enabled **will** cause significant lag. + /// Any values not passed to this function will *not* be dropped. #[inline] - pub fn run_forever(&mut self, callback: F) - where F: FnMut(Event) -> ControlFlow - { - self.events_loop.run_forever(callback) + pub fn run_forever(self, event_handler: impl 'static + EventHandler) -> ! { + self.events_loop.run_forever(event_handler) } /// Creates an `EventLoopProxy` that can be used to wake up the `EventLoop` from another diff --git a/src/platform/windows/drop_handler.rs b/src/platform/windows/drop_handler.rs index d3f28a9b36..b4357e1a8f 100644 --- a/src/platform/windows/drop_handler.rs +++ b/src/platform/windows/drop_handler.rs @@ -5,6 +5,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::{mem, ptr}; use std::rc::Rc; use std::cell::RefCell; +use std::collections::VecDeque; use winapi::ctypes::c_void; use winapi::shared::guiddef::REFIID; @@ -25,7 +26,7 @@ pub struct FileDropHandlerData { pub interface: IDropTarget, refcount: AtomicUsize, window: HWND, - event_queue: Rc>>, + event_queue: Rc>>, } pub struct FileDropHandler { @@ -34,7 +35,7 @@ pub struct FileDropHandler { #[allow(non_snake_case)] impl FileDropHandler { - pub fn new(window: HWND, event_queue: Rc>>) -> FileDropHandler { + pub fn new(window: HWND, event_queue: Rc>>) -> FileDropHandler { let data = Box::new(FileDropHandlerData { interface: IDropTarget { lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl, @@ -187,7 +188,7 @@ impl FileDropHandler { impl FileDropHandlerData { fn send_event(&self, event: Event) { - self.event_queue.borrow_mut().push(event); + self.event_queue.borrow_mut().push_back(event); } } diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index 17d6c526b1..5c588550a3 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -17,9 +17,8 @@ use winapi::shared::basetsd::UINT_PTR; use std::rc::Rc; use std::{mem, ptr}; use std::cell::RefCell; -use std::ffi::OsString; -use std::os::windows::ffi::OsStringExt; use std::sync::{Arc, Mutex}; +use std::collections::VecDeque; use winapi::ctypes::c_int; use winapi::shared::minwindef::{ @@ -35,14 +34,13 @@ use winapi::shared::minwindef::{ }; use winapi::shared::windef::{HWND, POINT, RECT}; use winapi::shared::windowsx; -use winapi::shared::winerror::S_OK; -use winapi::um::{winuser, processthreadsapi, ole2, shellapi, commctrl}; -use winapi::um::oleidl::LPDROPTARGET; +use winapi::um::{winuser, processthreadsapi, ole2, commctrl}; use winapi::um::winnt::{LONG, LPCSTR, SHORT}; use { ControlFlow, Event, + EventHandler, EventLoopClosed, KeyboardInput, LogicalPosition, @@ -110,13 +108,13 @@ pub struct WindowState { pub(crate) struct SubclassInput { pub window_state: Arc>, - pub event_queue: Rc>>, + pub event_queue: Rc>>, pub file_drop_handler: FileDropHandler } impl SubclassInput { fn send_event(&self, event: Event) { - self.event_queue.borrow_mut().push(event); + self.event_queue.borrow_mut().push_back(event); } } @@ -136,7 +134,7 @@ impl WindowState { pub struct EventLoop { // Id of the background thread from the Win32 API. thread_id: DWORD, - pub(crate) event_queue: Rc>> + pub(crate) event_queue: Rc>> } impl EventLoop { @@ -151,13 +149,15 @@ impl EventLoop { EventLoop { thread_id, - event_queue: Rc::new(RefCell::new(Vec::new())) + event_queue: Rc::new(RefCell::new(VecDeque::new())) } } - pub fn run_forever(&mut self, mut callback: F) - where F: FnMut(Event) -> ControlFlow - { + pub fn run_forever(self, mut event_handler: impl 'static + EventHandler) -> ! { + let event_loop = ::EventLoop { + events_loop: self, + _marker: ::std::marker::PhantomData + }; unsafe { // Calling `PostThreadMessageA` on a thread that does not have an events queue yet // will fail. In order to avoid this situation, we call `IsGuiThread` to initialize @@ -166,17 +166,17 @@ impl EventLoop { let mut msg = mem::uninitialized(); - loop { + 'main: loop { if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 { // Only happens if the message is `WM_QUIT`. debug_assert_eq!(msg.message, winuser::WM_QUIT); - return; + break 'main; } match msg.message { x if x == *WAKEUP_MSG_ID => { - if ControlFlow::Break == callback(Event::Awakened) { - return; + if ControlFlow::Break == event_handler.handle_event(Event::Awakened, &event_loop) { + break 'main; } }, x if x == *EXEC_MSG_ID => { @@ -184,20 +184,29 @@ impl EventLoop { function() } _ => { - // Calls `callback` below. + // Calls `event_handler` below. winuser::TranslateMessage(&msg); winuser::DispatchMessageW(&msg); } } - let mut event_queue = self.event_queue.borrow_mut(); - for event in event_queue.drain(..) { - if ControlFlow::Break == callback(event) { - return; + loop { + // For whatever reason doing this in a `whlie let` loop doesn't drop the `RefMut`, + // so we have to do it like this. + let event = match event_loop.events_loop.event_queue.borrow_mut().pop_front() { + Some(event) => event, + None => break + }; + + if ControlFlow::Break == event_handler.handle_event(event, &event_loop) { + break 'main; } } } } + + drop(event_handler); + ::std::process::exit(0); } pub fn create_proxy(&self) -> EventLoopProxy { From 8b8a7675ec67e15a0f8f69db0bdeb79bee0ac20d Mon Sep 17 00:00:00 2001 From: Osspial Date: Fri, 13 Jul 2018 01:48:26 -0400 Subject: [PATCH 05/40] Replace windows Mutex with parking_lot Mutex --- Cargo.toml | 4 +- src/lib.rs | 2 +- src/platform/windows/events_loop.rs | 29 ++++++------ src/platform/windows/window.rs | 70 ++++++++++++++++------------- 4 files changed, 59 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3ae8aa2d75..dc9ac5598a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,5 +63,7 @@ features = [ wayland-client = { version = "0.21", features = [ "dlopen", "egl", "cursor"] } smithay-client-toolkit = "0.4" x11-dl = "2.18.3" -parking_lot = "0.6" percent-encoding = "1.0" + +[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "windows"))'.dependencies.parking_lot] +version = "0.6" diff --git a/src/lib.rs b/src/lib.rs index bdfdb9928a..0cd3309d7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,7 +109,7 @@ extern crate core_foundation; extern crate core_graphics; #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] extern crate x11_dl; -#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] +#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "windows"))] extern crate parking_lot; #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] extern crate percent_encoding; diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index 5c588550a3..a206df6dc5 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -17,8 +17,9 @@ use winapi::shared::basetsd::UINT_PTR; use std::rc::Rc; use std::{mem, ptr}; use std::cell::RefCell; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::collections::VecDeque; +use parking_lot::Mutex; use winapi::ctypes::c_int; use winapi::shared::minwindef::{ @@ -463,7 +464,7 @@ pub unsafe extern "system" fn callback( winuser::WM_MOUSEMOVE => { use events::WindowEvent::{CursorEntered, CursorMoved}; let mouse_outside_window = { - let mut window = subclass_input.window_state.lock().unwrap(); + let mut window = subclass_input.window_state.lock(); if !window.mouse_in_window { window.mouse_in_window = true; true @@ -503,7 +504,7 @@ pub unsafe extern "system" fn callback( winuser::WM_MOUSELEAVE => { use events::WindowEvent::CursorLeft; let mouse_in_window = { - let mut window = subclass_input.window_state.lock().unwrap(); + let mut window = subclass_input.window_state.lock(); if window.mouse_in_window { window.mouse_in_window = false; true @@ -594,7 +595,7 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Left; use events::ElementState::Pressed; - capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap()); + capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), @@ -608,7 +609,7 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Left; use events::ElementState::Released; - release_mouse(&mut *subclass_input.window_state.lock().unwrap()); + release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), @@ -622,7 +623,7 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Right; use events::ElementState::Pressed; - capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap()); + capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), @@ -636,7 +637,7 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Right; use events::ElementState::Released; - release_mouse(&mut *subclass_input.window_state.lock().unwrap()); + release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), @@ -650,7 +651,7 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Middle; use events::ElementState::Pressed; - capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap()); + capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), @@ -664,7 +665,7 @@ pub unsafe extern "system" fn callback( use events::MouseButton::Middle; use events::ElementState::Released; - release_mouse(&mut *subclass_input.window_state.lock().unwrap()); + release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), @@ -679,7 +680,7 @@ pub unsafe extern "system" fn callback( use events::ElementState::Pressed; let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); - capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap()); + capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), @@ -694,7 +695,7 @@ pub unsafe extern "system" fn callback( use events::ElementState::Released; let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); - release_mouse(&mut *subclass_input.window_state.lock().unwrap()); + release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), @@ -893,7 +894,7 @@ pub unsafe extern "system" fn callback( winuser::WM_SETCURSOR => { let call_def_window_proc = { - let window_state = subclass_input.window_state.lock().unwrap(); + let window_state = subclass_input.window_state.lock(); if window_state.mouse_in_window { let cursor = winuser::LoadCursorW( ptr::null_mut(), @@ -921,7 +922,7 @@ pub unsafe extern "system" fn callback( winuser::WM_GETMINMAXINFO => { let mmi = lparam as *mut winuser::MINMAXINFO; - let window_state = subclass_input.window_state.lock().unwrap(); + let window_state = subclass_input.window_state.lock(); if window_state.min_size.is_some() || window_state.max_size.is_some() { let style = winuser::GetWindowLongA(window, winuser::GWL_STYLE) as DWORD; @@ -952,7 +953,7 @@ pub unsafe extern "system" fn callback( let new_dpi_factor = dpi_to_scale_factor(new_dpi_x); let suppress_resize = { - let mut window_state = subclass_input.window_state.lock().unwrap(); + let mut window_state = subclass_input.window_state.lock(); let suppress_resize = window_state.saved_window_info .as_mut() .map(|saved_window_info| { diff --git a/src/platform/windows/window.rs b/src/platform/windows/window.rs index 899e461077..49d9d15e3a 100644 --- a/src/platform/windows/window.rs +++ b/src/platform/windows/window.rs @@ -4,14 +4,15 @@ use std::{io, mem, ptr}; use std::cell::Cell; use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::sync::mpsc::channel; +use parking_lot::{Mutex, MutexGuard}; use winapi::ctypes::c_int; use winapi::shared::minwindef::{BOOL, DWORD, FALSE, LPARAM, TRUE, UINT, WORD, WPARAM}; use winapi::shared::windef::{HWND, LPPOINT, POINT, RECT}; use winapi::um::{combaseapi, dwmapi, libloaderapi, winuser, ole2}; -use winapi::um::objbase::COINIT_MULTITHREADED; +use winapi::um::objbase::COINIT_APARTMENTTHREADED; use winapi::um::shobjidl_core::{CLSID_TaskbarList, ITaskbarList2}; use winapi::um::wingdi::{CreateRectRgn, DeleteObject}; use winapi::um::oleidl::LPDROPTARGET; @@ -237,7 +238,7 @@ impl Window { } pub(crate) fn set_min_dimensions_physical(&self, dimensions: Option<(u32, u32)>) { - self.window_state.lock().unwrap().min_size = dimensions.map(Into::into); + self.window_state.lock().min_size = dimensions.map(Into::into); // Make windows re-check the window size bounds. self.get_inner_size_physical() .map(|(width, height)| self.set_inner_size_physical(width, height)); @@ -253,7 +254,7 @@ impl Window { } pub fn set_max_dimensions_physical(&self, dimensions: Option<(u32, u32)>) { - self.window_state.lock().unwrap().max_size = dimensions.map(Into::into); + self.window_state.lock().max_size = dimensions.map(Into::into); // Make windows re-check the window size bounds. self.get_inner_size_physical() .map(|(width, height)| self.set_inner_size_physical(width, height)); @@ -270,7 +271,7 @@ impl Window { #[inline] pub fn set_resizable(&self, resizable: bool) { - let mut window_state = self.window_state.lock().unwrap(); + let mut window_state = self.window_state.lock(); if mem::replace(&mut window_state.resizable, resizable) != resizable { // If we're in fullscreen, update stored configuration but don't apply anything. if window_state.fullscreen.is_none() { @@ -320,7 +321,7 @@ impl Window { MouseCursor::Help => winuser::IDC_HELP, _ => winuser::IDC_ARROW, // use arrow for the missing cases. }); - self.window_state.lock().unwrap().cursor = cursor_id; + self.window_state.lock().cursor = cursor_id; self.events_loop_proxy.execute_in_thread(move || unsafe { let cursor = winuser::LoadCursorW( ptr::null_mut(), @@ -376,7 +377,7 @@ impl Window { #[inline] pub fn grab_cursor(&self, grab: bool) -> Result<(), String> { let currently_grabbed = unsafe { self.cursor_is_grabbed() }?; - let window_state_lock = self.window_state.lock().unwrap(); + let window_state_lock = self.window_state.lock(); if currently_grabbed == grab && grab == window_state_lock.cursor_grabbed { return Ok(()); } @@ -386,7 +387,7 @@ impl Window { self.events_loop_proxy.execute_in_thread(move || { let result = unsafe { Self::grab_cursor_inner(&window, grab) }; if result.is_ok() { - window_state.lock().unwrap().cursor_grabbed = grab; + window_state.lock().cursor_grabbed = grab; } let _ = tx.send(result); }); @@ -404,14 +405,14 @@ impl Window { #[inline] pub fn hide_cursor(&self, hide: bool) { - let window_state_lock = self.window_state.lock().unwrap(); + let window_state_lock = self.window_state.lock(); // We don't want to increment/decrement the display count more than once! if hide == window_state_lock.cursor_hidden { return; } let (tx, rx) = channel(); let window_state = Arc::clone(&self.window_state); self.events_loop_proxy.execute_in_thread(move || { unsafe { Self::hide_cursor_inner(hide) }; - window_state.lock().unwrap().cursor_hidden = hide; + window_state.lock().cursor_hidden = hide; let _ = tx.send(()); }); drop(window_state_lock); @@ -420,7 +421,7 @@ impl Window { #[inline] pub fn get_hidpi_factor(&self) -> f64 { - self.window_state.lock().unwrap().dpi_factor + self.window_state.lock().dpi_factor } fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), String> { @@ -450,7 +451,7 @@ impl Window { #[inline] pub fn set_maximized(&self, maximized: bool) { - let mut window_state = self.window_state.lock().unwrap(); + let mut window_state = self.window_state.lock(); if mem::replace(&mut window_state.maximized, maximized) != maximized { // We only maximize if we're not in fullscreen. if window_state.fullscreen.is_none() { @@ -495,7 +496,7 @@ impl Window { (saved_window_info.style, saved_window_info.ex_style) } - unsafe fn restore_saved_window(&self, window_state_lock: &mut WindowState) { + unsafe fn restore_saved_window(&self, mut window_state_lock: MutexGuard) { let (rect, mut style, ex_style) = { // 'saved_window_info' can be None if the window has never been // in fullscreen mode before this method gets called. @@ -520,6 +521,7 @@ impl Window { let resizable = window_state_lock.resizable; let maximized = window_state_lock.maximized; + drop(window_state_lock); // We're restoring the window to its size and position from before being fullscreened. // `ShowWindow` resizes the window, so it must be called from the main thread. self.events_loop_proxy.execute_in_thread(move || { @@ -558,23 +560,31 @@ impl Window { mark_fullscreen(window.0, false); - let window_state_lock = window_state.lock().unwrap(); + let window_state_lock = window_state.lock(); let _ = Self::grab_cursor_inner(&window, window_state_lock.cursor_grabbed); }); } #[inline] pub fn set_fullscreen(&self, monitor: Option) { - let mut window_state_lock = self.window_state.lock().unwrap(); + let mut window_state_lock = self.window_state.lock(); unsafe { - match &monitor { - &Some(RootMonitorId { ref inner }) => { + let monitor_rect = monitor.as_ref() + .map(|RootMonitorId{ ref inner }| { let (x, y): (i32, i32) = inner.get_position().into(); let (width, height): (u32, u32) = inner.get_dimensions().into(); + (x, y, width, height) + }); + + match monitor_rect { + Some((x, y, width, height)) => { let window = self.window.clone(); let window_state = Arc::clone(&self.window_state); let (style, ex_style) = self.set_fullscreen_style(&mut window_state_lock); + window_state_lock.fullscreen = monitor; + drop(window_state_lock); + self.events_loop_proxy.execute_in_thread(move || { let _ = Self::grab_cursor_inner(&window, false); @@ -609,25 +619,24 @@ impl Window { mark_fullscreen(window.0, true); - let window_state_lock = window_state.lock().unwrap(); + let window_state_lock = window_state.lock(); let _ = Self::grab_cursor_inner(&window, window_state_lock.cursor_grabbed); }); - } - &None => { - self.restore_saved_window(&mut window_state_lock); + }, + None => { + window_state_lock.fullscreen = None; + self.restore_saved_window(window_state_lock) } } } - - window_state_lock.fullscreen = monitor; } #[inline] pub fn set_decorations(&self, decorations: bool) { - let mut window_state = self.window_state.lock().unwrap(); + let mut window_state = self.window_state.lock(); if mem::replace(&mut window_state.decorations, decorations) != decorations { - let style_flags = (winuser::WS_CAPTION | winuser::WS_THICKFRAME) as LONG; - let ex_style_flags = (winuser::WS_EX_WINDOWEDGE) as LONG; + let style_flags = (winuser::WS_CAPTION | winuser::WS_THICKFRAME) as LONG; + let ex_style_flags = (winuser::WS_EX_WINDOWEDGE) as LONG; // if we are in fullscreen mode, we only change the saved window info if window_state.fullscreen.is_some() { @@ -697,7 +706,7 @@ impl Window { #[inline] pub fn set_always_on_top(&self, always_on_top: bool) { - let mut window_state = self.window_state.lock().unwrap(); + let mut window_state = self.window_state.lock(); if mem::replace(&mut window_state.always_on_top, always_on_top) != always_on_top { let window = self.window.clone(); self.events_loop_proxy.execute_in_thread(move || { @@ -739,7 +748,7 @@ impl Window { } else { icon::unset_for_window(self.window.0, IconType::Small); } - self.window_state.lock().unwrap().window_icon = window_icon; + self.window_state.lock().window_icon = window_icon; } #[inline] @@ -752,7 +761,7 @@ impl Window { } else { icon::unset_for_window(self.window.0, IconType::Big); } - self.window_state.lock().unwrap().taskbar_icon = taskbar_icon; + self.window_state.lock().taskbar_icon = taskbar_icon; } #[inline] @@ -1057,6 +1066,7 @@ unsafe fn init( let file_drop_handler = { use winapi::shared::winerror::{OLE_E_WRONGCOMPOBJ, RPC_E_CHANGED_MODE, S_OK}; + let ole_init_result = ole2::OleInitialize(ptr::null_mut()); // It is ok if the initialize result is `S_FALSE` because it might happen that // multiple windows are created on the same thread. @@ -1136,7 +1146,7 @@ impl Drop for ComInitialized { thread_local!{ static COM_INITIALIZED: ComInitialized = { unsafe { - combaseapi::CoInitializeEx(ptr::null_mut(), COINIT_MULTITHREADED); + combaseapi::CoInitializeEx(ptr::null_mut(), COINIT_APARTMENTTHREADED); ComInitialized(ptr::null_mut()) } }; From 02f922f003f56215b92b8feeb9148ad2dd181fc2 Mon Sep 17 00:00:00 2001 From: Osspial Date: Fri, 17 Aug 2018 17:31:04 -0400 Subject: [PATCH 06/40] Implement new ControlFlow and associated events --- examples/cursor.rs | 8 +- examples/cursor_grab.rs | 10 +- examples/fullscreen.rs | 11 +-- examples/handling_close.rs | 8 +- examples/min_max_size.rs | 9 +- examples/multiwindow.rs | 8 +- examples/proxy.rs | 8 +- examples/resizable.rs | 8 +- examples/transparent.rs | 9 +- examples/window.rs | 6 +- examples/window_icon.rs | 8 +- src/events.rs | 35 +++++++ src/lib.rs | 84 ++++++---------- src/platform/windows/events_loop.rs | 148 ++++++++++++++++++++++------ 14 files changed, 233 insertions(+), 127 deletions(-) diff --git a/examples/cursor.rs b/examples/cursor.rs index 9feeb76c10..81a1a1cd33 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -3,14 +3,14 @@ extern crate winit; use winit::{Event, EventLoop, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow}; fn main() { - let mut events_loop = EventLoop::new(); + let events_loop = EventLoop::new(); let window = winit::WindowBuilder::new().build(&events_loop).unwrap(); window.set_title("A fantastic window!"); let mut cursor_idx = 0; - events_loop.run_forever(move |event, _: &EventLoop| { + events_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => { println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]); @@ -22,11 +22,11 @@ fn main() { } }, Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { - return ControlFlow::Break; + *control_flow = ControlFlow::Exit; + return; }, _ => () } - ControlFlow::Continue }); } diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index 11456f73c1..392a68d2e0 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -1,18 +1,19 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new() .with_title("Super Cursor Grab'n'Hide Simulator 9000") .build(&events_loop) .unwrap(); - events_loop.run_forever(move |event, _: &winit::EventLoop| { + events_loop.run(move |event, _, control_flow| { + *control_flow = winit::ControlFlow::Wait; if let winit::Event::WindowEvent { event, .. } = event { use winit::WindowEvent::*; match event { - CloseRequested => return winit::ControlFlow::Break, + CloseRequested => *control_flow = winit::ControlFlow::Exit, KeyboardInput { input: winit::KeyboardInput { state: winit::ElementState::Released, @@ -24,7 +25,7 @@ fn main() { } => { use winit::VirtualKeyCode::*; match key { - Escape => return winit::ControlFlow::Break, + Escape => *control_flow = winit::ControlFlow::Exit, G => window.grab_cursor(!modifiers.shift).unwrap(), H => window.hide_cursor(!modifiers.shift), _ => (), @@ -33,6 +34,5 @@ fn main() { _ => (), } } - winit::ControlFlow::Continue }); } diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index 84abb3518a..95afca0673 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -4,7 +4,7 @@ use std::io::{self, Write}; use winit::{ControlFlow, Event, WindowEvent}; fn main() { - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); // enumerating monitors let monitor = { @@ -35,12 +35,13 @@ fn main() { let mut is_maximized = false; let mut decorations = true; - events_loop.run_forever(move |event, _: &winit::EventLoop| { + events_loop.run(move |event, _, control_flow| { println!("{:?}", event); + *control_flow = ControlFlow::Wait; match event { Event::WindowEvent { event, .. } => match event { - WindowEvent::CloseRequested => return ControlFlow::Break, + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::KeyboardInput { input: winit::KeyboardInput { @@ -50,7 +51,7 @@ fn main() { }, .. } => match (virtual_code, state) { - (winit::VirtualKeyCode::Escape, _) => return ControlFlow::Break, + (winit::VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit, (winit::VirtualKeyCode::F, winit::ElementState::Pressed) => { is_fullscreen = !is_fullscreen; if !is_fullscreen { @@ -73,7 +74,5 @@ fn main() { }, _ => {} } - - ControlFlow::Continue }); } diff --git a/examples/handling_close.rs b/examples/handling_close.rs index 93d655bc65..b0189c3b71 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); let _window = winit::WindowBuilder::new() .with_title("Your faithful window") @@ -10,7 +10,7 @@ fn main() { let mut close_requested = false; - events_loop.run_forever(move |event, _: &winit::EventLoop| { + events_loop.run(move |event, _, control_flow| { use winit::WindowEvent::*; use winit::ElementState::Released; use winit::VirtualKeyCode::{N, Y}; @@ -53,7 +53,7 @@ fn main() { // event loop (i.e. if it's a multi-window application), you need to // drop the window. That closes it, and results in `Destroyed` being // sent. - return winit::ControlFlow::Break; + *control_flow = winit::ControlFlow::Exit; } } N => { @@ -69,6 +69,6 @@ fn main() { _ => (), } - winit::ControlFlow::Continue + *control_flow = winit::ControlFlow::Wait; }); } diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index f011920bf7..88d4823d89 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -3,7 +3,7 @@ extern crate winit; use winit::dpi::LogicalSize; fn main() { - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new() .build(&events_loop) @@ -12,12 +12,13 @@ fn main() { window.set_min_dimensions(Some(LogicalSize::new(400.0, 200.0))); window.set_max_dimensions(Some(LogicalSize::new(800.0, 400.0))); - events_loop.run_forever(move |event, _: &winit::EventLoop| { + events_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { - winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => winit::ControlFlow::Break, - _ => winit::ControlFlow::Continue, + winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => + *control_flow = winit::ControlFlow::Exit, + _ => *control_flow = winit::ControlFlow::Wait, } }); } diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index 3dfabf8922..c4278828df 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -3,7 +3,7 @@ extern crate winit; use std::collections::HashMap; fn main() { - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); let mut windows = HashMap::new(); for _ in 0..3 { @@ -11,7 +11,8 @@ fn main() { windows.insert(window.id(), window); } - events_loop.run_forever(move |event, events_loop: &winit::EventLoop| { + events_loop.run(move |event, events_loop, control_flow| { + *control_flow = winit::ControlFlow::Wait; match event { winit::Event::WindowEvent { event, window_id } => { match event { @@ -22,7 +23,7 @@ fn main() { windows.remove(&window_id); if windows.is_empty() { - return winit::ControlFlow::Break; + *control_flow = winit::ControlFlow::Exit; } }, winit::WindowEvent::KeyboardInput{..} => { @@ -34,6 +35,5 @@ fn main() { } _ => (), } - winit::ControlFlow::Continue }) } diff --git a/examples/proxy.rs b/examples/proxy.rs index 4df2efe4f9..c9f7bf751a 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); let _window = winit::WindowBuilder::new() .with_title("A fantastic window!") @@ -18,12 +18,12 @@ fn main() { } }); - events_loop.run_forever(move |event, _: &winit::EventLoop| { + events_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => - winit::ControlFlow::Break, - _ => winit::ControlFlow::Continue, + *control_flow = winit::ControlFlow::Wait, + _ => *control_flow = winit::ControlFlow::Wait, } }); } diff --git a/examples/resizable.rs b/examples/resizable.rs index c84fe5b052..fd75860d8d 100644 --- a/examples/resizable.rs +++ b/examples/resizable.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); let mut resizable = false; @@ -12,10 +12,11 @@ fn main() { .build(&events_loop) .unwrap(); - events_loop.run_forever(move |event, _: &winit::EventLoop| { + events_loop.run(move |event, _, control_flow| { + *control_flow = winit::ControlFlow::Wait; match event { winit::Event::WindowEvent { event, .. } => match event { - winit::WindowEvent::CloseRequested => return winit::ControlFlow::Break, + winit::WindowEvent::CloseRequested => *control_flow = winit::ControlFlow::Exit, winit::WindowEvent::KeyboardInput { input: winit::KeyboardInput { @@ -33,6 +34,5 @@ fn main() { }, _ => (), }; - winit::ControlFlow::Continue }); } diff --git a/examples/transparent.rs b/examples/transparent.rs index 7cfed50566..321b907163 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -1,7 +1,7 @@ extern crate winit; fn main() { - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new().with_decorations(false) .with_transparency(true) @@ -9,12 +9,13 @@ fn main() { window.set_title("A fantastic window!"); - events_loop.run_forever(move |event, _: &winit::EventLoop| { + events_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { - winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => winit::ControlFlow::Break, - _ => winit::ControlFlow::Continue, + winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => + *control_flow = winit::ControlFlow::Exit, + _ => *control_flow = winit::ControlFlow::Wait, } }); } diff --git a/examples/window.rs b/examples/window.rs index e46386744f..5c6f753e8a 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -8,15 +8,15 @@ fn main() { .build(&events_loop) .unwrap(); - events_loop.run_forever(move |event, _: &winit::EventLoop| { + events_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. - } => winit::ControlFlow::Break, - _ => winit::ControlFlow::Continue, + } => *control_flow = winit::ControlFlow::Exit, + _ => *control_flow = winit::ControlFlow::Wait, } }); } diff --git a/examples/window_icon.rs b/examples/window_icon.rs index fc54c5394c..691ec09ad8 100644 --- a/examples/window_icon.rs +++ b/examples/window_icon.rs @@ -20,7 +20,7 @@ fn main() { // feature enabled). let icon = Icon::from_path(path).expect("Failed to open icon"); - let mut events_loop = winit::EventLoop::new(); + let events_loop = winit::EventLoop::new(); let window = winit::WindowBuilder::new() .with_title("An iconic window!") @@ -30,11 +30,12 @@ fn main() { .build(&events_loop) .unwrap(); - events_loop.run_forever(move |event, _: &EventLoop| { + events_loop.run(move |event, _, control_flow| { + *control_flow = winit::ControlFlow::Wait; if let winit::Event::WindowEvent { event, .. } = event { use winit::WindowEvent::*; match event { - CloseRequested => return winit::ControlFlow::Break, + CloseRequested => *control_flow = winit::ControlFlow::Exit, DroppedFile(path) => { use image::GenericImageView; @@ -81,7 +82,6 @@ fn main() { _ => (), } } - winit::ControlFlow::Continue }); } diff --git a/src/events.rs b/src/events.rs index c740c29770..8951ed6f2d 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,3 +1,4 @@ +use std::time::{Duration, Instant}; use std::path::PathBuf; use {DeviceId, LogicalPosition, LogicalSize, WindowId}; @@ -14,6 +15,15 @@ pub enum Event { event: DeviceEvent, }, Awakened, + /// Emitted when new events arrive from the OS to be processed. + NewEvents(StartCause), + /// Emitted when all of the event loop's events have been processed and control flow is about + /// to be taken away from the program. + EventsCleared, + + /// Emitted when the event loop is being shut down. This is irreversable - if this event is + /// emitted, it is guaranteed to be the last event emitted. + LoopDestroyed, /// The application has been suspended or resumed. /// @@ -21,6 +31,31 @@ pub enum Event { Suspended(bool), } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum StartCause { + /// Sent if the time specified by `ControlFlow::WaitTimeout` has been elapsed. Contains the + /// moment the timeout was requested and the requested duration of the timeout. The actual + /// duration is guaranteed to be greater than or equal to the requested timeout. + TimeoutExpired { + start: Instant, + requested_duration: Duration, + }, + + /// Sent if the OS has new events to send to the window, after a wait was requested. Contains + /// the moment the wait was requested, and if a wait timout was requested, its duration. + WaitCancelled { + start: Instant, + requested_duration: Option + }, + + /// Sent if the event loop is being resumed after the loop's control flow was set to + /// `ControlFlow::Poll`. + Poll, + + /// Sent once, immediately after `run` is called. Indicates that the loop was just initialized. + Init +} + /// Describes an event from a `Window`. #[derive(Clone, Debug, PartialEq)] pub enum WindowEvent { diff --git a/src/lib.rs b/src/lib.rs index 0cd3309d7d..cce680b140 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,47 +28,21 @@ //! The events generated by a window can be retreived from the `EventLoop` the window was created //! with. //! -//! There are two ways to do so. The first is to call `events_loop.poll_events(...)`, which will -//! retrieve all the events pending on the windows and immediately return after no new event is -//! available. You usually want to use this method in application that render continuously on the -//! screen, such as video games. -//! -//! ```no_run -//! use winit::{Event, WindowEvent}; -//! use winit::dpi::LogicalSize; -//! # use winit::EventLoop; -//! # let mut events_loop = EventLoop::new(); -//! -//! loop { -//! events_loop.poll_events(|event| { -//! match event { -//! Event::WindowEvent { -//! event: WindowEvent::Resized(LogicalSize { width, height }), -//! .. -//! } => { -//! println!("The window was resized to {}x{}", width, height); -//! }, -//! _ => () -//! } -//! }); -//! } -//! ``` -//! -//! 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::Break`. +//! You do this by calling `events_loop.run(...)`. This function will run forever unless it is +//! stopped by returning `ControlFlow::Exit`, at which point the entire program will terminate. //! //! ```no_run //! use winit::{ControlFlow, Event, WindowEvent}; //! # use winit::EventLoop; -//! # let mut events_loop = EventLoop::new(); +//! # let events_loop = EventLoop::new(); //! -//! events_loop.run_forever(move |event, _: &EventLoop| { +//! events_loop.run(move |event, _, control_flow| { //! match event { //! Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { //! println!("The close button was pressed; stopping"); -//! ControlFlow::Break +//! *control_flow = ControlFlow::Exit //! }, -//! _ => ControlFlow::Continue, +//! _ => *control_flow = ControlFlow::Wait, //! } //! }); //! ``` @@ -116,6 +90,7 @@ extern crate percent_encoding; #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] extern crate smithay_client_toolkit as sctk; +use std::time::Duration; pub(crate) use dpi::*; // TODO: Actually change the imports throughout the codebase. pub use events::*; pub use window::{AvailableMonitorsIter, MonitorId}; @@ -139,12 +114,12 @@ pub mod os; /// let mut events_loop = EventLoop::new(); /// let window = Window::new(&events_loop).unwrap(); /// -/// events_loop.run_forever(move |event, _: &EventLoop| { +/// events_loop.run(move |event, _, control_flow| { /// match event { /// Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { -/// ControlFlow::Break +/// *control_flow = ControlFlow::Exit /// }, -/// _ => ControlFlow::Continue, +/// _ => *control_flow = ControlFlow::Wait, /// } /// }); /// ``` @@ -199,28 +174,29 @@ impl std::fmt::Debug for EventLoop { } } -pub trait EventHandler { - fn handle_event(&mut self, event: Event, event_loop: &EventLoop) -> ControlFlow; -} - -impl EventHandler for F - where F: FnMut(Event, &EventLoop) -> ControlFlow -{ - fn handle_event(&mut self, event: Event, event_loop: &EventLoop) -> ControlFlow { - self(event, event_loop) - } -} - /// Returned by the user callback given to the `EventLoop::run_forever` method. /// /// Indicates whether the `run_forever` method should continue or complete. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ControlFlow { - /// Continue looping and waiting for events. - Continue, - /// Break from the event loop. - Break, + /// When the current loop iteration finishes, suspend the thread until another event arrives. + Wait, + /// When the current loop iteration finishes, suspend the thread until either another event + /// arrives or the timeout expires. + WaitTimeout(Duration), + /// When the current loop iteration finishes, immediately begin a new iteration regardless of + /// whether or not new events are available to process. + Poll, + /// Send a `LoopDestroyed` event and stop the event loop. + Exit +} + +impl Default for ControlFlow { + #[inline(always)] + fn default() -> ControlFlow { + ControlFlow::Poll + } } impl EventLoop { @@ -257,8 +233,10 @@ impl EventLoop { /// /// Any values not passed to this function will *not* be dropped. #[inline] - pub fn run_forever(self, event_handler: impl 'static + EventHandler) -> ! { - self.events_loop.run_forever(event_handler) + pub fn run(self, event_handler: F) -> ! + where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow) + { + self.events_loop.run(event_handler) } /// Creates an `EventLoopProxy` that can be used to wake up the `EventLoop` from another diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index a206df6dc5..dac7ca2ad7 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -19,6 +19,7 @@ use std::{mem, ptr}; use std::cell::RefCell; use std::sync::Arc; use std::collections::VecDeque; +use std::time::{Duration, Instant}; use parking_lot::Mutex; use winapi::ctypes::c_int; @@ -35,13 +36,12 @@ use winapi::shared::minwindef::{ }; use winapi::shared::windef::{HWND, POINT, RECT}; use winapi::shared::windowsx; -use winapi::um::{winuser, processthreadsapi, ole2, commctrl}; +use winapi::um::{winuser, winbase, processthreadsapi, ole2, commctrl}; use winapi::um::winnt::{LONG, LPCSTR, SHORT}; use { ControlFlow, Event, - EventHandler, EventLoopClosed, KeyboardInput, LogicalPosition, @@ -50,7 +50,7 @@ use { WindowEvent, WindowId as SuperWindowId, }; -use events::{DeviceEvent, Touch, TouchPhase}; +use events::{DeviceEvent, Touch, TouchPhase, StartCause}; use platform::platform::{event, Cursor, WindowId, DEVICE_ID, wrap_device_id, util}; use platform::platform::dpi::{ become_dpi_aware, @@ -154,11 +154,16 @@ impl EventLoop { } } - pub fn run_forever(self, mut event_handler: impl 'static + EventHandler) -> ! { + pub fn run(self, mut event_handler: F) -> ! + where F: 'static + FnMut(Event, &::EventLoop, &mut ControlFlow) + { let event_loop = ::EventLoop { events_loop: self, _marker: ::std::marker::PhantomData }; + let mut control_flow = ControlFlow::default(); + let mut timer_handle = 0; + unsafe { // Calling `PostThreadMessageA` on a thread that does not have an events queue yet // will fail. In order to avoid this situation, we call `IsGuiThread` to initialize @@ -168,44 +173,109 @@ impl EventLoop { let mut msg = mem::uninitialized(); 'main: loop { - if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 { - // Only happens if the message is `WM_QUIT`. - debug_assert_eq!(msg.message, winuser::WM_QUIT); - break 'main; + macro_rules! call_event_handler { + ($event:expr) => {{ + event_handler($event, &event_loop, &mut control_flow); + if ControlFlow::Exit == control_flow { + break 'main; + } + }} } - match msg.message { - x if x == *WAKEUP_MSG_ID => { - if ControlFlow::Break == event_handler.handle_event(Event::Awakened, &event_loop) { + let mut has_message = true; + let new_events_cause: StartCause; + match control_flow { + ControlFlow::Wait => { + let wait_start = Instant::now(); + if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 { + // Only happens if the message is `WM_QUIT`. + debug_assert_eq!(msg.message, winuser::WM_QUIT); break 'main; } - }, - x if x == *EXEC_MSG_ID => { - let mut function: Box> = Box::from_raw(msg.wParam as usize as *mut _); - function() + new_events_cause = + StartCause::WaitCancelled { + start: wait_start, + requested_duration: None + }; } - _ => { - // Calls `event_handler` below. - winuser::TranslateMessage(&msg); - winuser::DispatchMessageW(&msg); + ControlFlow::WaitTimeout(duration) => { + let new_handle = winuser::SetTimer(ptr::null_mut(), timer_handle, dur2timeout(duration), None); + if timer_handle == 0 { + timer_handle = new_handle; + } + let wait_start = Instant::now(); + if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 { + // Only happens if the message is `WM_QUIT`. + debug_assert_eq!(msg.message, winuser::WM_QUIT); + break 'main; + } + if msg.message == winuser::WM_TIMER && msg.wParam == timer_handle { + new_events_cause = + StartCause::TimeoutExpired { + start: wait_start, + requested_duration: duration, + }; + if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { + has_message = false; + } + } else { + new_events_cause = + StartCause::WaitCancelled { + start: wait_start, + requested_duration: Some(duration) + }; + } } + ControlFlow::Poll => { + if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { + has_message = false; + } + new_events_cause = StartCause::Poll; + } + ControlFlow::Exit => break 'main } + call_event_handler!(Event::NewEvents(new_events_cause)); - loop { - // For whatever reason doing this in a `whlie let` loop doesn't drop the `RefMut`, - // so we have to do it like this. - let event = match event_loop.events_loop.event_queue.borrow_mut().pop_front() { - Some(event) => event, - None => break - }; + while has_message { + match msg.message { + x if x == *WAKEUP_MSG_ID => { + call_event_handler!(Event::Awakened); + }, + x if x == *EXEC_MSG_ID => { + let mut function: Box> = Box::from_raw(msg.wParam as usize as *mut _); + function() + } + _ => { + // Calls `event_handler` below. + winuser::TranslateMessage(&msg); + winuser::DispatchMessageW(&msg); + } + } + + loop { + // For whatever reason doing this in a `whlie let` loop doesn't drop the `RefMut`, + // so we have to do it like this. + let event = match event_loop.events_loop.event_queue.borrow_mut().pop_front() { + Some(event) => event, + None => break + }; + + call_event_handler!(event); + } - if ControlFlow::Break == event_handler.handle_event(event, &event_loop) { - break 'main; + if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { + has_message = false; } } + call_event_handler!(Event::EventsCleared); + } + + if timer_handle != 0 { + winuser::KillTimer(ptr::null_mut(), timer_handle); } } + event_handler(Event::LoopDestroyed, &event_loop, &mut control_flow); drop(event_handler); ::std::process::exit(0); } @@ -217,6 +287,28 @@ impl EventLoop { } } +// Implementation taken from https://github.com/rust-lang/rust/blob/db5476571d9b27c862b95c1e64764b0ac8980e23/src/libstd/sys/windows/mod.rs +pub fn dur2timeout(dur: Duration) -> DWORD { + // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the + // timeouts in windows APIs are typically u32 milliseconds. To translate, we + // have two pieces to take care of: + // + // * Nanosecond precision is rounded up + // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE + // (never time out). + dur.as_secs().checked_mul(1000).and_then(|ms| { + ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000) + }).and_then(|ms| { + ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 {1} else {0}) + }).map(|ms| { + if ms > DWORD::max_value() as u64 { + winbase::INFINITE + } else { + ms as DWORD + } + }).unwrap_or(winbase::INFINITE) +} + impl Drop for EventLoop { fn drop(&mut self) { unsafe { From a0b2bb36953f018ff782cef8fc86c6db9343095d Mon Sep 17 00:00:00 2001 From: Osspial Date: Fri, 17 Aug 2018 17:49:46 -0400 Subject: [PATCH 07/40] Add StartCause::Init support, timer example --- examples/timer.rs | 33 +++++++++++++++++++++++++++++ src/platform/windows/events_loop.rs | 1 + 2 files changed, 34 insertions(+) create mode 100644 examples/timer.rs diff --git a/examples/timer.rs b/examples/timer.rs new file mode 100644 index 0000000000..7e849b0298 --- /dev/null +++ b/examples/timer.rs @@ -0,0 +1,33 @@ +extern crate winit; +use std::time::{Duration, Instant}; + +fn main() { + let events_loop = winit::EventLoop::new(); + + let _window = winit::WindowBuilder::new() + .with_title("A fantastic window!") + .build(&events_loop) + .unwrap(); + + events_loop.run(move |event, _, control_flow| { + println!("{:?}", event); + + match event { + winit::Event::NewEvents(winit::StartCause::Init) => + *control_flow = winit::ControlFlow::WaitTimeout(Duration::new(1, 0)), + winit::Event::NewEvents(winit::StartCause::TimeoutExpired{..}) => { + *control_flow = winit::ControlFlow::WaitTimeout(Duration::new(1, 0)); + println!("\nTimer\n"); + }, + winit::Event::NewEvents(winit::StartCause::WaitCancelled{start, requested_duration}) => { + println!("{:?}", Instant::now() - start); + *control_flow = winit::ControlFlow::WaitTimeout(requested_duration.unwrap().checked_sub(Instant::now() - start).unwrap_or(Duration::new(0, 0))); + } + winit::Event::WindowEvent { + event: winit::WindowEvent::CloseRequested, + .. + } => *control_flow = winit::ControlFlow::Exit, + _ => () + } + }); +} diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index dac7ca2ad7..fbaa0d0080 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -172,6 +172,7 @@ impl EventLoop { let mut msg = mem::uninitialized(); + event_handler(Event::NewEvents(StartCause::Init), &event_loop, &mut control_flow); 'main: loop { macro_rules! call_event_handler { ($event:expr) => {{ From 2c607ff87f8fbcad8aa9dc3783b3298c014dd177 Mon Sep 17 00:00:00 2001 From: Osspial Date: Sun, 19 Aug 2018 13:44:22 -0400 Subject: [PATCH 08/40] Add ability to send custom user events --- Cargo.toml | 3 + README.md | 6 +- examples/proxy.rs | 11 ++- src/events.rs | 19 +++- src/lib.rs | 41 ++++---- src/os/windows.rs | 2 +- src/platform/windows/drop_handler.rs | 14 ++- src/platform/windows/events_loop.rs | 138 ++++++++++++++++----------- src/platform/windows/monitor.rs | 16 ++-- src/platform/windows/window.rs | 40 ++++---- src/window.rs | 4 +- tests/send_objects.rs | 2 +- 12 files changed, 176 insertions(+), 120 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dc9ac5598a..11641f863a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,9 @@ cocoa = "0.18.4" core-foundation = "0.6" core-graphics = "0.17.3" +[target.'cfg(target_os = "windows")'.dependencies.crossbeam-channel] +version = "0.3" + [target.'cfg(target_os = "windows")'.dependencies.winapi] version = "0.3.6" features = [ diff --git a/README.md b/README.md index 5f5771bc27..0fbf3b0017 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,10 @@ another library. extern crate winit; fn main() { - let mut events_loop = winit::EventsLoop::new(); - let window = winit::Window::new(&events_loop).unwrap(); + let mut event_loop = winit::EventLoop::new(); + let window = winit::Window::new(&event_loop).unwrap(); - events_loop.run_forever(|event| { + event_loop.run(|event| { match event { winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, diff --git a/examples/proxy.rs b/examples/proxy.rs index c9f7bf751a..fe648ed66b 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -1,9 +1,10 @@ extern crate winit; +use winit::{EventLoop, WindowBuilder}; fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop: EventLoop = EventLoop::new_user_event(); - let _window = winit::WindowBuilder::new() + let _window = WindowBuilder::new() .with_title("A fantastic window!") .build(&events_loop) .unwrap(); @@ -11,10 +12,12 @@ fn main() { let proxy = events_loop.create_proxy(); std::thread::spawn(move || { + let mut counter = 0; // Wake up the `events_loop` once every second. loop { std::thread::sleep(std::time::Duration::from_secs(1)); - proxy.wakeup().unwrap(); + proxy.send_event(counter).unwrap(); + counter += 1; } }); @@ -22,7 +25,7 @@ fn main() { println!("{:?}", event); match event { winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => - *control_flow = winit::ControlFlow::Wait, + *control_flow = winit::ControlFlow::Exit, _ => *control_flow = winit::ControlFlow::Wait, } }); diff --git a/src/events.rs b/src/events.rs index 8951ed6f2d..6726fa3b2f 100644 --- a/src/events.rs +++ b/src/events.rs @@ -5,7 +5,7 @@ use {DeviceId, LogicalPosition, LogicalSize, WindowId}; /// Describes a generic event. #[derive(Clone, Debug, PartialEq)] -pub enum Event { +pub enum Event { WindowEvent { window_id: WindowId, event: WindowEvent, @@ -14,7 +14,7 @@ pub enum Event { device_id: DeviceId, event: DeviceEvent, }, - Awakened, + UserEvent(T), /// Emitted when new events arrive from the OS to be processed. NewEvents(StartCause), /// Emitted when all of the event loop's events have been processed and control flow is about @@ -31,6 +31,21 @@ pub enum Event { Suspended(bool), } +impl Event { + pub fn map_nonuser_event(self) -> Result, Event> { + use self::Event::*; + match self { + UserEvent(_) => Err(self), + WindowEvent{window_id, event} => Ok(WindowEvent{window_id, event}), + DeviceEvent{device_id, event} => Ok(DeviceEvent{device_id, event}), + NewEvents(cause) => Ok(NewEvents(cause)), + EventsCleared => Ok(EventsCleared), + LoopDestroyed => Ok(LoopDestroyed), + Suspended(suspended) => Ok(Suspended(suspended)), + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum StartCause { /// Sent if the time specified by `ControlFlow::WaitTimeout` has been elapsed. Contains the diff --git a/src/lib.rs b/src/lib.rs index cce680b140..8c1ec73d20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,6 +72,9 @@ extern crate serde; #[cfg(target_os = "windows")] extern crate winapi; +#[cfg(target_os = "windows")] +#[macro_use] +extern crate crossbeam_channel; #[cfg(any(target_os = "macos", target_os = "ios"))] #[macro_use] extern crate objc; @@ -163,12 +166,12 @@ pub struct DeviceId(platform::DeviceId); /// forbiding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the /// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the /// `EventLoopProxy` allows you to wakeup an `EventLoop` from an other thread. -pub struct EventLoop { - events_loop: platform::EventLoop, +pub struct EventLoop { + events_loop: platform::EventLoop, _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync } -impl std::fmt::Debug for EventLoop { +impl std::fmt::Debug for EventLoop { fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { fmtr.pad("EventLoop { .. }") } @@ -199,14 +202,20 @@ impl Default for ControlFlow { } } -impl EventLoop { +impl EventLoop<()> { + pub fn new() -> EventLoop<()> { + EventLoop::<()>::new_user_event() + } +} + +impl EventLoop { /// Builds a new events loop. /// /// Usage will result in display backend initialisation, this can be controlled on linux /// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`. /// If it is not set, winit will try to connect to a wayland connection, and if it fails will /// fallback on x11. If this variable is set with any other value, winit will panic. - pub fn new() -> EventLoop { + pub fn new_user_event() -> EventLoop { EventLoop { events_loop: platform::EventLoop::new(), _marker: ::std::marker::PhantomData, @@ -234,14 +243,14 @@ impl EventLoop { /// Any values not passed to this function will *not* be dropped. #[inline] pub fn run(self, event_handler: F) -> ! - where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow) + where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow) { self.events_loop.run(event_handler) } /// Creates an `EventLoopProxy` that can be used to wake up the `EventLoop` from another /// thread. - pub fn create_proxy(&self) -> EventLoopProxy { + pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { events_loop_proxy: self.events_loop.create_proxy(), } @@ -250,24 +259,24 @@ impl EventLoop { /// Used to wake up the `EventLoop` from another thread. #[derive(Clone)] -pub struct EventLoopProxy { - events_loop_proxy: platform::EventLoopProxy, +pub struct EventLoopProxy { + events_loop_proxy: platform::EventLoopProxy, } -impl std::fmt::Debug for EventLoopProxy { +impl std::fmt::Debug for EventLoopProxy { fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { fmtr.pad("EventLoopProxy { .. }") } } -impl EventLoopProxy { - /// Wake up the `EventLoop` from which this proxy was created. - /// - /// This causes the `EventLoop` to emit an `Awakened` event. +impl EventLoopProxy { + /// Send an event to the `EventLoop` from which this proxy was created. This emits a + /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this + /// function. /// /// Returns an `Err` if the associated `EventLoop` no longer exists. - pub fn wakeup(&self) -> Result<(), EventLoopClosed> { - self.events_loop_proxy.wakeup() + pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { + self.events_loop_proxy.send_event(event) } } diff --git a/src/os/windows.rs b/src/os/windows.rs index 41e3ac1c4c..6a5b67df1f 100644 --- a/src/os/windows.rs +++ b/src/os/windows.rs @@ -15,7 +15,7 @@ pub trait EventLoopExt { fn new_dpi_unaware() -> Self where Self: Sized; } -impl EventLoopExt for EventLoop { +impl EventLoopExt for EventLoop { #[inline] fn new_dpi_unaware() -> Self { EventLoop { diff --git a/src/platform/windows/drop_handler.rs b/src/platform/windows/drop_handler.rs index b4357e1a8f..99a1920a70 100644 --- a/src/platform/windows/drop_handler.rs +++ b/src/platform/windows/drop_handler.rs @@ -3,9 +3,7 @@ use std::os::windows::ffi::OsStringExt; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use std::{mem, ptr}; -use std::rc::Rc; -use std::cell::RefCell; -use std::collections::VecDeque; +use crossbeam_channel::Sender; use winapi::ctypes::c_void; use winapi::shared::guiddef::REFIID; @@ -26,7 +24,7 @@ pub struct FileDropHandlerData { pub interface: IDropTarget, refcount: AtomicUsize, window: HWND, - event_queue: Rc>>, + event_sender: Sender> } pub struct FileDropHandler { @@ -35,14 +33,14 @@ pub struct FileDropHandler { #[allow(non_snake_case)] impl FileDropHandler { - pub fn new(window: HWND, event_queue: Rc>>) -> FileDropHandler { + pub fn new(window: HWND, event_sender: Sender>) -> FileDropHandler { let data = Box::new(FileDropHandlerData { interface: IDropTarget { lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl, }, refcount: AtomicUsize::new(1), window, - event_queue, + event_sender, }); FileDropHandler { data: Box::into_raw(data), @@ -187,8 +185,8 @@ impl FileDropHandler { } impl FileDropHandlerData { - fn send_event(&self, event: Event) { - self.event_queue.borrow_mut().push_back(event); + fn send_event(&self, event: Event<()>) { + self.event_sender.send(event).ok(); } } diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index fbaa0d0080..a808b78190 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -14,13 +14,11 @@ use winapi::shared::basetsd::DWORD_PTR; use winapi::shared::basetsd::UINT_PTR; -use std::rc::Rc; use std::{mem, ptr}; -use std::cell::RefCell; use std::sync::Arc; -use std::collections::VecDeque; use std::time::{Duration, Instant}; use parking_lot::Mutex; +use crossbeam_channel::{self, Sender, Receiver}; use winapi::ctypes::c_int; use winapi::shared::minwindef::{ @@ -107,18 +105,6 @@ pub struct WindowState { pub mouse_buttons_down: u32 } -pub(crate) struct SubclassInput { - pub window_state: Arc>, - pub event_queue: Rc>>, - pub file_drop_handler: FileDropHandler -} - -impl SubclassInput { - fn send_event(&self, event: Event) { - self.event_queue.borrow_mut().push_back(event); - } -} - impl WindowState { pub fn update_min_max(&mut self, old_dpi_factor: f64, new_dpi_factor: f64) { let scale_factor = new_dpi_factor / old_dpi_factor; @@ -132,30 +118,55 @@ impl WindowState { } } -pub struct EventLoop { +pub(crate) struct SubclassInput { + pub window_state: Arc>, + pub event_send: Sender>, + pub file_drop_handler: FileDropHandler +} + +impl SubclassInput { + fn send_event(&self, event: Event<()>) { + self.event_send.send(event).ok(); + } +} + +pub struct EventLoop { // Id of the background thread from the Win32 API. thread_id: DWORD, - pub(crate) event_queue: Rc>> + + pub(crate) event_send: Sender>, + pub(crate) user_event_send: Sender, + + event_recv: Receiver>, + user_event_recv: Receiver } -impl EventLoop { - pub fn new() -> EventLoop { +impl EventLoop { + pub fn new() -> EventLoop { Self::with_dpi_awareness(true) } - pub fn with_dpi_awareness(dpi_aware: bool) -> EventLoop { + pub fn with_dpi_awareness(dpi_aware: bool) -> EventLoop { become_dpi_aware(dpi_aware); let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; + let (event_send, event_recv) = crossbeam_channel::unbounded(); + let (user_event_send, user_event_recv) = crossbeam_channel::unbounded(); + EventLoop { thread_id, - event_queue: Rc::new(RefCell::new(VecDeque::new())) + + event_send, + event_recv, + + user_event_send, + user_event_recv, } } pub fn run(self, mut event_handler: F) -> ! - where F: 'static + FnMut(Event, &::EventLoop, &mut ControlFlow) + where F: 'static + FnMut(Event, &::EventLoop, &mut ControlFlow) { let event_loop = ::EventLoop { events_loop: self, @@ -239,9 +250,8 @@ impl EventLoop { while has_message { match msg.message { - x if x == *WAKEUP_MSG_ID => { - call_event_handler!(Event::Awakened); - }, + // Handler is called in loop below. + x if x == *WAKEUP_MSG_ID => (), x if x == *EXEC_MSG_ID => { let mut function: Box> = Box::from_raw(msg.wParam as usize as *mut _); function() @@ -254,14 +264,16 @@ impl EventLoop { } loop { - // For whatever reason doing this in a `whlie let` loop doesn't drop the `RefMut`, - // so we have to do it like this. - let event = match event_loop.events_loop.event_queue.borrow_mut().pop_front() { - Some(event) => event, - None => break + let full_event: Option> = select! { + recv(event_loop.events_loop.event_recv) -> event => + event.ok().map(|e| e.map_nonuser_event().expect("User event sent through nonuser channel")), + recv(event_loop.events_loop.user_event_recv) -> user_event => + user_event.ok().map(|e| Event::UserEvent(e)), + default => break }; - - call_event_handler!(event); + if let Some(full_event) = full_event { + call_event_handler!(full_event); + } } if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { @@ -281,9 +293,17 @@ impl EventLoop { ::std::process::exit(0); } - pub fn create_proxy(&self) -> EventLoopProxy { + pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { thread_id: self.thread_id, + event_send: self.user_event_send.clone() + } + } + + #[inline(always)] + pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor { + EventLoopThreadExecutor { + thread_id: self.thread_id } } } @@ -310,7 +330,7 @@ pub fn dur2timeout(dur: Duration) -> DWORD { }).unwrap_or(winbase::INFINITE) } -impl Drop for EventLoop { +impl Drop for EventLoop { fn drop(&mut self) { unsafe { // Posting `WM_QUIT` will cause `GetMessage` to stop. @@ -319,29 +339,11 @@ impl Drop for EventLoop { } } -#[derive(Clone)] -pub struct EventLoopProxy { - thread_id: DWORD, +pub(crate) struct EventLoopThreadExecutor { + thread_id: DWORD } -impl EventLoopProxy { - pub fn wakeup(&self) -> Result<(), EventLoopClosed> { - unsafe { - if winuser::PostThreadMessageA(self.thread_id, *WAKEUP_MSG_ID, 0, 0) != 0 { - Ok(()) - } else { - // https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms644946(v=vs.85).aspx - // > If the function fails, the return value is zero. To get extended error - // > information, call GetLastError. GetLastError returns ERROR_INVALID_THREAD_ID - // > if idThread is not a valid thread identifier, or if the thread specified by - // > idThread does not have a message queue. GetLastError returns - // > ERROR_NOT_ENOUGH_QUOTA when the message limit is hit. - // TODO: handle ERROR_NOT_ENOUGH_QUOTA - Err(EventLoopClosed) - } - } - } - +impl EventLoopThreadExecutor { /// Check to see if we're in the parent event loop's thread. pub(super) fn in_event_loop_thread(&self) -> bool { let cur_thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; @@ -384,6 +386,32 @@ impl EventLoopProxy { } } +#[derive(Clone)] +pub struct EventLoopProxy { + thread_id: DWORD, + event_send: Sender +} + +impl EventLoopProxy { + pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { + unsafe { + if winuser::PostThreadMessageA(self.thread_id, *WAKEUP_MSG_ID, 0, 0) != 0 { + self.event_send.send(event).ok(); + Ok(()) + } else { + // https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms644946(v=vs.85).aspx + // > If the function fails, the return value is zero. To get extended error + // > information, call GetLastError. GetLastError returns ERROR_INVALID_THREAD_ID + // > if idThread is not a valid thread identifier, or if the thread specified by + // > idThread does not have a message queue. GetLastError returns + // > ERROR_NOT_ENOUGH_QUOTA when the message limit is hit. + // TODO: handle ERROR_NOT_ENOUGH_QUOTA + Err(EventLoopClosed) + } + } + } +} + lazy_static! { // Message sent by the `EventLoopProxy` when we want to wake up the thread. // WPARAM and LPARAM are unused. diff --git a/src/platform/windows/monitor.rs b/src/platform/windows/monitor.rs index 760d392456..b8a562ac2a 100644 --- a/src/platform/windows/monitor.rs +++ b/src/platform/windows/monitor.rs @@ -71,19 +71,19 @@ pub fn get_primary_monitor() -> MonitorId { MonitorId::from_hmonitor(hmonitor) } -impl EventLoop { +pub fn get_current_monitor(hwnd: HWND) -> MonitorId { + let hmonitor = unsafe { + winuser::MonitorFromWindow(hwnd, winuser::MONITOR_DEFAULTTONEAREST) + }; + MonitorId::from_hmonitor(hmonitor) +} + +impl EventLoop { // TODO: Investigate opportunities for caching pub fn get_available_monitors(&self) -> VecDeque { get_available_monitors() } - pub fn get_current_monitor(hwnd: HWND) -> MonitorId { - let hmonitor = unsafe { - winuser::MonitorFromWindow(hwnd, winuser::MONITOR_DEFAULTTONEAREST) - }; - MonitorId::from_hmonitor(hmonitor) - } - pub fn get_primary_monitor(&self) -> MonitorId { get_primary_monitor() } diff --git a/src/platform/windows/window.rs b/src/platform/windows/window.rs index 49d9d15e3a..547e4371a1 100644 --- a/src/platform/windows/window.rs +++ b/src/platform/windows/window.rs @@ -32,7 +32,7 @@ use platform::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, Window use platform::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi}; use platform::platform::events_loop::{self, DESTROY_MSG_ID, EventLoop, INITIAL_DPI_MSG_ID, WindowState}; use platform::platform::icon::{self, IconType, WinIcon}; -use platform::platform::monitor::get_available_monitors; +use platform::platform::monitor; use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input; use platform::platform::drop_handler::FileDropHandler; use platform::platform::util; @@ -48,7 +48,7 @@ pub struct Window { window_state: Arc>, // The events loop proxy. - events_loop_proxy: events_loop::EventLoopProxy, + thread_executor: events_loop::EventLoopThreadExecutor, } // https://blogs.msdn.microsoft.com/oldnewthing/20131017-00/?p=2903 @@ -74,8 +74,8 @@ unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> B } impl Window { - pub fn new( - events_loop: &EventLoop, + pub fn new( + events_loop: &EventLoop, w_attr: WindowAttributes, pl_attr: PlatformSpecificWindowBuilderAttributes, ) -> Result { @@ -322,7 +322,7 @@ impl Window { _ => winuser::IDC_ARROW, // use arrow for the missing cases. }); self.window_state.lock().cursor = cursor_id; - self.events_loop_proxy.execute_in_thread(move || unsafe { + self.thread_executor.execute_in_thread(move || unsafe { let cursor = winuser::LoadCursorW( ptr::null_mut(), cursor_id.0, @@ -384,7 +384,7 @@ impl Window { let window = self.window.clone(); let window_state = Arc::clone(&self.window_state); let (tx, rx) = channel(); - self.events_loop_proxy.execute_in_thread(move || { + self.thread_executor.execute_in_thread(move || { let result = unsafe { Self::grab_cursor_inner(&window, grab) }; if result.is_ok() { window_state.lock().cursor_grabbed = grab; @@ -410,7 +410,7 @@ impl Window { if hide == window_state_lock.cursor_hidden { return; } let (tx, rx) = channel(); let window_state = Arc::clone(&self.window_state); - self.events_loop_proxy.execute_in_thread(move || { + self.thread_executor.execute_in_thread(move || { unsafe { Self::hide_cursor_inner(hide) }; window_state.lock().cursor_hidden = hide; let _ = tx.send(()); @@ -458,7 +458,7 @@ impl Window { let window = self.window.clone(); unsafe { // `ShowWindow` resizes the window, so it must be called from the main thread. - self.events_loop_proxy.execute_in_thread(move || { + self.thread_executor.execute_in_thread(move || { winuser::ShowWindow( window.0, if maximized { @@ -524,7 +524,7 @@ impl Window { drop(window_state_lock); // We're restoring the window to its size and position from before being fullscreened. // `ShowWindow` resizes the window, so it must be called from the main thread. - self.events_loop_proxy.execute_in_thread(move || { + self.thread_executor.execute_in_thread(move || { let _ = Self::grab_cursor_inner(&window, false); if resizable { @@ -585,7 +585,7 @@ impl Window { window_state_lock.fullscreen = monitor; drop(window_state_lock); - self.events_loop_proxy.execute_in_thread(move || { + self.thread_executor.execute_in_thread(move || { let _ = Self::grab_cursor_inner(&window, false); winuser::SetWindowLongW( @@ -681,7 +681,7 @@ impl Window { let window = self.window.clone(); - self.events_loop_proxy.execute_in_thread(move || { + self.thread_executor.execute_in_thread(move || { winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style); winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style); winuser::AdjustWindowRectEx(&mut rect, style as _, 0, ex_style as _); @@ -709,7 +709,7 @@ impl Window { let mut window_state = self.window_state.lock(); if mem::replace(&mut window_state.always_on_top, always_on_top) != always_on_top { let window = self.window.clone(); - self.events_loop_proxy.execute_in_thread(move || { + self.thread_executor.execute_in_thread(move || { let insert_after = if always_on_top { winuser::HWND_TOPMOST } else { @@ -734,7 +734,7 @@ impl Window { #[inline] pub fn get_current_monitor(&self) -> RootMonitorId { RootMonitorId { - inner: EventLoop::get_current_monitor(self.window.0), + inner: monitor::get_current_monitor(self.window.0), } } @@ -809,10 +809,10 @@ pub unsafe fn adjust_size( (rect.right - rect.left, rect.bottom - rect.top) } -unsafe fn init( +unsafe fn init( mut attributes: WindowAttributes, mut pl_attribs: PlatformSpecificWindowBuilderAttributes, - event_loop: &events_loop::EventLoop, + event_loop: &events_loop::EventLoop, ) -> Result { let title = OsStr::new(&attributes.title) .encode_wide() @@ -848,7 +848,7 @@ unsafe fn init( let class_name = register_window_class(&window_icon, &taskbar_icon); let guessed_dpi_factor = { - let monitors = get_available_monitors(); + let monitors = monitor::get_available_monitors(); let dpi_factor = if !monitors.is_empty() { let mut dpi_factor = Some(monitors[0].get_hidpi_factor()); for monitor in &monitors { @@ -1055,7 +1055,7 @@ unsafe fn init( let win = Window { window: real_window, window_state, - events_loop_proxy: event_loop.create_proxy(), + thread_executor: event_loop.create_thread_executor(), }; win.set_maximized(attributes.maximized); @@ -1076,7 +1076,7 @@ unsafe fn init( panic!("OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`"); } - let file_drop_handler = FileDropHandler::new(win.window.0, event_loop.event_queue.clone()); + let file_drop_handler = FileDropHandler::new(win.window.0, event_loop.event_send.clone()); let handler_interface_ptr = &mut (*file_drop_handler.data).interface as LPDROPTARGET; assert_eq!(ole2::RegisterDragDrop(win.window.0, handler_interface_ptr), S_OK); @@ -1085,8 +1085,8 @@ unsafe fn init( let subclass_input = events_loop::SubclassInput { window_state: win.window_state.clone(), - event_queue: event_loop.event_queue.clone(), - file_drop_handler + event_send: event_loop.event_send.clone(), + file_drop_handler, }; events_loop::subclass_window(win.window.0, subclass_input); diff --git a/src/window.rs b/src/window.rs index 604fc9fe60..6468099fd3 100644 --- a/src/window.rs +++ b/src/window.rs @@ -142,7 +142,7 @@ impl WindowBuilder { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn build(mut self, events_loop: &EventLoop) -> Result { + pub fn build(mut self, events_loop: &EventLoop) -> Result { self.window.dimensions = Some(self.window.dimensions.unwrap_or_else(|| { if let Some(ref monitor) = self.window.fullscreen { // resizing the window to the dimensions of the monitor when fullscreen @@ -170,7 +170,7 @@ impl Window { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn new(events_loop: &EventLoop) -> Result { + pub fn new(events_loop: &EventLoop) -> Result { let builder = WindowBuilder::new(); builder.build(events_loop) } diff --git a/tests/send_objects.rs b/tests/send_objects.rs index d0a34fd024..6cb0fe43c9 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -5,7 +5,7 @@ fn needs_send() {} #[test] fn events_loop_proxy_send() { // ensures that `winit::EventLoopProxy` implements `Send` - needs_send::(); + needs_send::>(); } #[test] From a0fef1a5fad9b5d5da59fff191c7d9c398ea9e01 Mon Sep 17 00:00:00 2001 From: Osspial Date: Mon, 20 Aug 2018 01:47:11 -0400 Subject: [PATCH 09/40] Fully invert windows control flow so win32 calls into winit's callback --- examples/timer.rs | 19 +- src/events.rs | 16 +- src/lib.rs | 6 +- src/platform/windows/drop_handler.rs | 8 +- src/platform/windows/events_loop.rs | 588 ++++++++++++++++++++------- src/platform/windows/window.rs | 77 ++-- 6 files changed, 510 insertions(+), 204 deletions(-) diff --git a/examples/timer.rs b/examples/timer.rs index 7e849b0298..3df30c919b 100644 --- a/examples/timer.rs +++ b/examples/timer.rs @@ -1,5 +1,6 @@ extern crate winit; use std::time::{Duration, Instant}; +use winit::{Event, WindowEvent, StartCause, ControlFlow}; fn main() { let events_loop = winit::EventLoop::new(); @@ -13,20 +14,16 @@ fn main() { println!("{:?}", event); match event { - winit::Event::NewEvents(winit::StartCause::Init) => - *control_flow = winit::ControlFlow::WaitTimeout(Duration::new(1, 0)), - winit::Event::NewEvents(winit::StartCause::TimeoutExpired{..}) => { - *control_flow = winit::ControlFlow::WaitTimeout(Duration::new(1, 0)); + Event::NewEvents(StartCause::Init) => + *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0)), + Event::NewEvents(StartCause::ResumeTimeReached{..}) => { + *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0)); println!("\nTimer\n"); }, - winit::Event::NewEvents(winit::StartCause::WaitCancelled{start, requested_duration}) => { - println!("{:?}", Instant::now() - start); - *control_flow = winit::ControlFlow::WaitTimeout(requested_duration.unwrap().checked_sub(Instant::now() - start).unwrap_or(Duration::new(0, 0))); - } - winit::Event::WindowEvent { - event: winit::WindowEvent::CloseRequested, + Event::WindowEvent { + event: WindowEvent::CloseRequested, .. - } => *control_flow = winit::ControlFlow::Exit, + } => *control_flow = ControlFlow::Exit, _ => () } }); diff --git a/src/events.rs b/src/events.rs index 6726fa3b2f..407afdfe45 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,4 +1,4 @@ -use std::time::{Duration, Instant}; +use std::time::Instant; use std::path::PathBuf; use {DeviceId, LogicalPosition, LogicalSize, WindowId}; @@ -48,19 +48,19 @@ impl Event { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum StartCause { - /// Sent if the time specified by `ControlFlow::WaitTimeout` has been elapsed. Contains the - /// moment the timeout was requested and the requested duration of the timeout. The actual - /// duration is guaranteed to be greater than or equal to the requested timeout. - TimeoutExpired { + /// Sent if the time specified by `ControlFlow::WaitUntil` has been reached. Contains the + /// moment the timeout was requested and the requested resume time. The actual resume time is + /// guaranteed to be equal to or after the requested resume time. + ResumeTimeReached { start: Instant, - requested_duration: Duration, + requested_resume: Instant }, /// Sent if the OS has new events to send to the window, after a wait was requested. Contains - /// the moment the wait was requested, and if a wait timout was requested, its duration. + /// the moment the wait was requested and the resume time, if requested. WaitCancelled { start: Instant, - requested_duration: Option + requested_resume: Option }, /// Sent if the event loop is being resumed after the loop's control flow was set to diff --git a/src/lib.rs b/src/lib.rs index 8c1ec73d20..3b7a1fc161 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,7 @@ extern crate percent_encoding; #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] extern crate smithay_client_toolkit as sctk; -use std::time::Duration; +use std::time::Instant; pub(crate) use dpi::*; // TODO: Actually change the imports throughout the codebase. pub use events::*; pub use window::{AvailableMonitorsIter, MonitorId}; @@ -186,8 +186,8 @@ pub enum ControlFlow { /// When the current loop iteration finishes, suspend the thread until another event arrives. Wait, /// When the current loop iteration finishes, suspend the thread until either another event - /// arrives or the timeout expires. - WaitTimeout(Duration), + /// arrives or the given time is reached. + WaitUntil(Instant), /// When the current loop iteration finishes, immediately begin a new iteration regardless of /// whether or not new events are available to process. Poll, diff --git a/src/platform/windows/drop_handler.rs b/src/platform/windows/drop_handler.rs index 99a1920a70..43ba47d74b 100644 --- a/src/platform/windows/drop_handler.rs +++ b/src/platform/windows/drop_handler.rs @@ -24,7 +24,7 @@ pub struct FileDropHandlerData { pub interface: IDropTarget, refcount: AtomicUsize, window: HWND, - event_sender: Sender> + // event_sender: Sender> } pub struct FileDropHandler { @@ -33,14 +33,14 @@ pub struct FileDropHandler { #[allow(non_snake_case)] impl FileDropHandler { - pub fn new(window: HWND, event_sender: Sender>) -> FileDropHandler { + pub fn new(window: HWND/*, event_sender: Sender>*/) -> FileDropHandler { let data = Box::new(FileDropHandlerData { interface: IDropTarget { lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl, }, refcount: AtomicUsize::new(1), window, - event_sender, + // event_sender, }); FileDropHandler { data: Box::into_raw(data), @@ -186,7 +186,7 @@ impl FileDropHandler { impl FileDropHandlerData { fn send_event(&self, event: Event<()>) { - self.event_sender.send(event).ok(); + // self.event_sender.send(event).ok(); } } diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index a808b78190..c8a1c6b3ab 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -17,6 +17,8 @@ use winapi::shared::basetsd::UINT_PTR; use std::{mem, ptr}; use std::sync::Arc; use std::time::{Duration, Instant}; +use std::rc::Rc; +use std::cell::RefCell; use parking_lot::Mutex; use crossbeam_channel::{self, Sender, Receiver}; @@ -34,7 +36,7 @@ use winapi::shared::minwindef::{ }; use winapi::shared::windef::{HWND, POINT, RECT}; use winapi::shared::windowsx; -use winapi::um::{winuser, winbase, processthreadsapi, ole2, commctrl}; +use winapi::um::{winuser, winbase, ole2, processthreadsapi, commctrl, libloaderapi}; use winapi::um::winnt::{LONG, LPCSTR, SHORT}; use { @@ -102,7 +104,8 @@ pub struct WindowState { pub always_on_top: bool, pub maximized: bool, pub resizable: bool, - pub mouse_buttons_down: u32 + pub mouse_buttons_down: u32, + pub modal_timer_handle: UINT_PTR } impl WindowState { @@ -118,27 +121,45 @@ impl WindowState { } } -pub(crate) struct SubclassInput { +pub(crate) struct SubclassInput { pub window_state: Arc>, - pub event_send: Sender>, - pub file_drop_handler: FileDropHandler + pub event_loop_runner: EventLoopRunnerShared, + pub file_drop_handler: FileDropHandler, } -impl SubclassInput { - fn send_event(&self, event: Event<()>) { - self.event_send.send(event).ok(); +impl SubclassInput { + unsafe fn send_event(&self, event: Event) { + let runner = self.event_loop_runner.borrow_mut(); + if let Some(runner) = *runner { + (*runner).process_event(event); + } else { + panic!("Attempted to send event without active runner"); + } + } +} + +struct ThreadMsgTargetSubclassInput { + event_loop_runner: EventLoopRunnerShared, + user_event_receiver: Receiver +} + +impl ThreadMsgTargetSubclassInput { + unsafe fn send_event(&self, event: Event) { + let runner = self.event_loop_runner.borrow_mut(); + if let Some(runner) = *runner { + (*runner).process_event(event); + } else { + panic!("Attempted to send event without active runner"); + } } } pub struct EventLoop { // Id of the background thread from the Win32 API. thread_id: DWORD, - - pub(crate) event_send: Sender>, - pub(crate) user_event_send: Sender, - - event_recv: Receiver>, - user_event_recv: Receiver + thread_msg_target: HWND, + thread_msg_sender: Sender, + pub(crate) runner_shared: EventLoopRunnerShared, } impl EventLoop { @@ -150,153 +171,88 @@ impl EventLoop { become_dpi_aware(dpi_aware); let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; - - let (event_send, event_recv) = crossbeam_channel::unbounded(); - let (user_event_send, user_event_recv) = crossbeam_channel::unbounded(); + let runner_shared = Rc::new(RefCell::new(None)); + let (thread_msg_target, thread_msg_sender) = thread_event_target_window(runner_shared.clone()); EventLoop { thread_id, - - event_send, - event_recv, - - user_event_send, - user_event_recv, + thread_msg_target, thread_msg_sender, + runner_shared } } pub fn run(self, mut event_handler: F) -> ! where F: 'static + FnMut(Event, &::EventLoop, &mut ControlFlow) { - let event_loop = ::EventLoop { - events_loop: self, - _marker: ::std::marker::PhantomData - }; - let mut control_flow = ControlFlow::default(); - let mut timer_handle = 0; - unsafe { - // Calling `PostThreadMessageA` on a thread that does not have an events queue yet - // will fail. In order to avoid this situation, we call `IsGuiThread` to initialize - // it. winuser::IsGUIThread(1); + let mut runner = EventLoopRunner { + event_loop: ::EventLoop { + events_loop: self, + _marker: ::std::marker::PhantomData + }, + control_flow: ControlFlow::default(), + runner_state: RunnerState::New, + modal_loop_data: None, + event_handler: &mut event_handler + }; + *runner.event_loop.events_loop.runner_shared.borrow_mut() = Some(&mut runner); + let timer_handle = winuser::SetTimer(ptr::null_mut(), 0, 0x7FFFFFFF, None); + let mut msg = mem::uninitialized(); + let mut msg_unprocessed = false; - event_handler(Event::NewEvents(StartCause::Init), &event_loop, &mut control_flow); 'main: loop { - macro_rules! call_event_handler { - ($event:expr) => {{ - event_handler($event, &event_loop, &mut control_flow); - if ControlFlow::Exit == control_flow { - break 'main; + runner.new_events(); + loop { + if !msg_unprocessed { + if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { + break; } - }} + } + winuser::TranslateMessage(&mut msg); + winuser::DispatchMessageW(&mut msg); + msg_unprocessed = false; } + runner.events_cleared(); - let mut has_message = true; - let new_events_cause: StartCause; - match control_flow { + match runner.control_flow { + ControlFlow::Exit => break 'main, ControlFlow::Wait => { - let wait_start = Instant::now(); - if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 { - // Only happens if the message is `WM_QUIT`. - debug_assert_eq!(msg.message, winuser::WM_QUIT); - break 'main; + if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { + break 'main } - new_events_cause = - StartCause::WaitCancelled { - start: wait_start, - requested_duration: None - }; + msg_unprocessed = true; } - ControlFlow::WaitTimeout(duration) => { - let new_handle = winuser::SetTimer(ptr::null_mut(), timer_handle, dur2timeout(duration), None); - if timer_handle == 0 { - timer_handle = new_handle; - } - let wait_start = Instant::now(); - if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 { - // Only happens if the message is `WM_QUIT`. - debug_assert_eq!(msg.message, winuser::WM_QUIT); - break 'main; - } - if msg.message == winuser::WM_TIMER && msg.wParam == timer_handle { - new_events_cause = - StartCause::TimeoutExpired { - start: wait_start, - requested_duration: duration, - }; - if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { - has_message = false; + ControlFlow::WaitUntil(resume_time) => { + let now = Instant::now(); + if now <= resume_time { + let duration = resume_time - now; + winuser::SetTimer(ptr::null_mut(), timer_handle, dur2timeout(duration), None); + if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { + break 'main } - } else { - new_events_cause = - StartCause::WaitCancelled { - start: wait_start, - requested_duration: Some(duration) - }; + winuser::SetTimer(ptr::null_mut(), timer_handle, 0x7FFFFFFF, None); + msg_unprocessed = true; } - } - ControlFlow::Poll => { - if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { - has_message = false; - } - new_events_cause = StartCause::Poll; - } - ControlFlow::Exit => break 'main + }, + ControlFlow::Poll => () } - call_event_handler!(Event::NewEvents(new_events_cause)); - - while has_message { - match msg.message { - // Handler is called in loop below. - x if x == *WAKEUP_MSG_ID => (), - x if x == *EXEC_MSG_ID => { - let mut function: Box> = Box::from_raw(msg.wParam as usize as *mut _); - function() - } - _ => { - // Calls `event_handler` below. - winuser::TranslateMessage(&msg); - winuser::DispatchMessageW(&msg); - } - } - - loop { - let full_event: Option> = select! { - recv(event_loop.events_loop.event_recv) -> event => - event.ok().map(|e| e.map_nonuser_event().expect("User event sent through nonuser channel")), - recv(event_loop.events_loop.user_event_recv) -> user_event => - user_event.ok().map(|e| Event::UserEvent(e)), - default => break - }; - if let Some(full_event) = full_event { - call_event_handler!(full_event); - } - } - - if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { - has_message = false; - } - } - call_event_handler!(Event::EventsCleared); } - if timer_handle != 0 { - winuser::KillTimer(ptr::null_mut(), timer_handle); - } + runner.call_event_handler(Event::LoopDestroyed); + *runner.event_loop.events_loop.runner_shared.borrow_mut() = None; } - event_handler(Event::LoopDestroyed, &event_loop, &mut control_flow); drop(event_handler); ::std::process::exit(0); } pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { - thread_id: self.thread_id, - event_send: self.user_event_send.clone() + target_window: self.thread_msg_target, + event_send: self.thread_msg_sender.clone() } } @@ -308,8 +264,201 @@ impl EventLoop { } } +pub(crate) type EventLoopRunnerShared = Rc>>>; +pub(crate) struct EventLoopRunner { + event_loop: ::EventLoop, + control_flow: ControlFlow, + runner_state: RunnerState, + modal_loop_data: Option, + event_handler: *mut FnMut(Event, &::EventLoop, &mut ControlFlow) +} + +struct ModalLoopData { + hwnd: HWND, + timer_handle: UINT_PTR +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum RunnerState { + /// The event loop has just been created, and an `Init` event must be sent. + New, + /// The event loop is idling, and began idling at the given instant. + Idle(Instant), + /// The event loop has received a signal from the OS that the loop may resume, but no winit + /// events have been generated yet. We're waiting for an event to be processed or the events + /// to be marked as cleared to send `NewEvents`, depending on the current `ControlFlow`. + DeferredNewEvents(Instant), + /// The event loop is handling the OS's events and sending them to the user's callback. + /// `NewEvents` has been sent, and `EventsCleared` hasn't. + HandlingEvents, +} + +impl EventLoopRunner { + unsafe fn new_events(&mut self) { + self.runner_state = match self.runner_state { + // If we're already handling events or have deferred `NewEvents`, we don't need to do + // do any processing. + RunnerState::HandlingEvents | + RunnerState::DeferredNewEvents(..) => self.runner_state, + + // Send the `Init` `NewEvents` and immediately move into event processing. + RunnerState::New => { + self.call_event_handler(Event::NewEvents(StartCause::Init)); + RunnerState::HandlingEvents + }, + + // When `NewEvents` gets sent after an idle depends on the control flow... + RunnerState::Idle(wait_start) => { + match self.control_flow { + // If we're polling, send `NewEvents` and immediately move into event processing. + ControlFlow::Poll => { + self.call_event_handler(Event::NewEvents(StartCause::Poll)); + RunnerState::HandlingEvents + }, + // If the user was waiting until a specific time, the `NewEvents` call gets sent + // at varying times depending on the current time. + ControlFlow::WaitUntil(resume_time) => { + match Instant::now() >= resume_time { + // If the current time is later than the requested resume time, we can tell the + // user that the resume time has been reached with `NewEvents` and immdiately move + // into event processing. + true => { + self.call_event_handler(Event::NewEvents(StartCause::ResumeTimeReached { + start: wait_start, + requested_resume: resume_time + })); + RunnerState::HandlingEvents + }, + // However, if the current time is EARLIER than the requested resume time, we + // don't want to send the `WaitCancelled` event until we know an event is being + // sent. Defer. + false => RunnerState::DeferredNewEvents(wait_start) + } + }, + // If we're waiting, `NewEvents` doesn't get sent until winit gets an event, so + // we defer. + ControlFlow::Wait | + // `Exit` shouldn't really ever get sent here, but if it does do something somewhat sane. + ControlFlow::Exit => RunnerState::DeferredNewEvents(wait_start), + } + } + }; + } + + unsafe fn process_event(&mut self, event: Event) { + if let Some(ModalLoopData{hwnd, timer_handle}) = self.modal_loop_data { + if !self.event_processing_active() { + winuser::SetTimer(hwnd, timer_handle, 0, None); + } + } + + // If new event processing has to be done (i.e. call NewEvents or defer), do it. If we're + // already in processing nothing happens with this call. + self.new_events(); + + // Now that an event has been received, we have to send any `NewEvents` calls that were + // deferred. + if let RunnerState::DeferredNewEvents(wait_start) = self.runner_state { + match self.control_flow { + ControlFlow::Wait => self.call_event_handler( + Event::NewEvents(StartCause::WaitCancelled { + start: wait_start, + requested_resume: None + }) + ), + ControlFlow::WaitUntil(resume_time) => { + let start_cause = match Instant::now() >= resume_time { + // If the current time is later than the requested resume time, the resume time + // has been reached. + true => StartCause::ResumeTimeReached { + start: wait_start, + requested_resume: resume_time + }, + // Otherwise, the requested resume time HASN'T been reached and we send a WaitCancelled. + false => StartCause::WaitCancelled { + start: wait_start, + requested_resume: Some(resume_time) + }, + }; + self.call_event_handler(Event::NewEvents(start_cause)); + }, + ControlFlow::Poll | + ControlFlow::Exit => unreachable!() + } + + self.runner_state = RunnerState::HandlingEvents; + } + + self.call_event_handler(event); + } + + unsafe fn events_cleared(&mut self) { + match self.runner_state { + // If we were handling events, send the EventsCleared message. + RunnerState::HandlingEvents => { + self.call_event_handler(Event::EventsCleared); + self.runner_state = RunnerState::Idle(Instant::now()); + }, + + // If we *weren't* handling events, we don't have to do anything. + RunnerState::New | + RunnerState::Idle(..) => (), + + // Some control flows require a NewEvents call even if no events were received. This + // branch handles those. + RunnerState::DeferredNewEvents(wait_start) => { + match self.control_flow { + // If we had deferred a Poll, send the Poll NewEvents and EventsCleared. + ControlFlow::Poll => { + self.call_event_handler(Event::NewEvents(StartCause::Poll)); + self.call_event_handler(Event::EventsCleared); + }, + // If we had deferred a WaitUntil and the resume time has since been reached, + // send the resume notification and EventsCleared event. + ControlFlow::WaitUntil(resume_time) => { + if Instant::now() >= resume_time { + self.call_event_handler(Event::NewEvents(StartCause::ResumeTimeReached { + start: wait_start, + requested_resume: resume_time + })); + self.call_event_handler(Event::EventsCleared); + } + }, + // If we deferred a wait and no events were received, the user doesn't have to + // get an event. + ControlFlow::Wait | + ControlFlow::Exit => () + } + // Mark that we've entered an idle state. + self.runner_state = RunnerState::Idle(wait_start) + }, + } + } + + unsafe fn call_event_handler(&mut self, event: Event) { + if self.event_handler != mem::zeroed() { + if self.control_flow != ControlFlow::Exit { + (*self.event_handler)(event, &self.event_loop, &mut self.control_flow); + } else { + (*self.event_handler)(event, &self.event_loop, &mut ControlFlow::Exit); + } + } else { + panic!("Tried to call event handler with null handler"); + } + } + + fn event_processing_active(&self) -> bool { + match self.runner_state { + RunnerState::HandlingEvents => true, + RunnerState::DeferredNewEvents(..) | + RunnerState::New | + RunnerState::Idle(..) => false + } + } +} + // Implementation taken from https://github.com/rust-lang/rust/blob/db5476571d9b27c862b95c1e64764b0ac8980e23/src/libstd/sys/windows/mod.rs -pub fn dur2timeout(dur: Duration) -> DWORD { +fn dur2timeout(dur: Duration) -> DWORD { // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the // timeouts in windows APIs are typically u32 milliseconds. To translate, we // have two pieces to take care of: @@ -333,6 +482,7 @@ pub fn dur2timeout(dur: Duration) -> DWORD { impl Drop for EventLoop { fn drop(&mut self) { unsafe { + winuser::DestroyWindow(self.thread_msg_target); // Posting `WM_QUIT` will cause `GetMessage` to stop. winuser::PostThreadMessageA(self.thread_id, winuser::WM_QUIT, 0, 0); } @@ -388,24 +538,18 @@ impl EventLoopThreadExecutor { #[derive(Clone)] pub struct EventLoopProxy { - thread_id: DWORD, + target_window: HWND, event_send: Sender } +unsafe impl Send for EventLoopProxy {} impl EventLoopProxy { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { unsafe { - if winuser::PostThreadMessageA(self.thread_id, *WAKEUP_MSG_ID, 0, 0) != 0 { + if winuser::PostMessageW(self.target_window, *USER_EVENT_MSG_ID, 0, 0) != 0 { self.event_send.send(event).ok(); Ok(()) } else { - // https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms644946(v=vs.85).aspx - // > If the function fails, the return value is zero. To get extended error - // > information, call GetLastError. GetLastError returns ERROR_INVALID_THREAD_ID - // > if idThread is not a valid thread identifier, or if the thread specified by - // > idThread does not have a message queue. GetLastError returns - // > ERROR_NOT_ENOUGH_QUOTA when the message limit is hit. - // TODO: handle ERROR_NOT_ENOUGH_QUOTA Err(EventLoopClosed) } } @@ -415,7 +559,7 @@ impl EventLoopProxy { lazy_static! { // Message sent by the `EventLoopProxy` when we want to wake up the thread. // WPARAM and LPARAM are unused. - static ref WAKEUP_MSG_ID: u32 = { + static ref USER_EVENT_MSG_ID: u32 = { unsafe { winuser::RegisterWindowMessageA("Winit::WakeupMsg\0".as_ptr() as LPCSTR) } @@ -442,6 +586,68 @@ lazy_static! { winuser::RegisterWindowMessageA("Winit::InitialDpiMsg\0".as_ptr() as LPCSTR) } }; + static ref THREAD_EVENT_TARGET_WINDOW_CLASS: Vec = unsafe { + use std::ffi::OsStr; + use std::os::windows::ffi::OsStrExt; + + let class_name: Vec<_> = OsStr::new("Winit Thread Event Target") + .encode_wide() + .chain(Some(0).into_iter()) + .collect(); + + let class = winuser::WNDCLASSEXW { + cbSize: mem::size_of::() as UINT, + style: 0, + lpfnWndProc: Some(winuser::DefWindowProcW), + cbClsExtra: 0, + cbWndExtra: 0, + hInstance: libloaderapi::GetModuleHandleW(ptr::null()), + hIcon: ptr::null_mut(), + hCursor: ptr::null_mut(), // must be null in order for cursor state to work properly + hbrBackground: ptr::null_mut(), + lpszMenuName: ptr::null(), + lpszClassName: class_name.as_ptr(), + hIconSm: ptr::null_mut(), + }; + + winuser::RegisterClassExW(&class); + + class_name + }; +} + +fn thread_event_target_window(event_loop_runner: EventLoopRunnerShared) -> (HWND, Sender) { + unsafe { + let window = winuser::CreateWindowExW( + 0, + THREAD_EVENT_TARGET_WINDOW_CLASS.as_ptr(), + ptr::null_mut(), + 0, + 0, 0, + 0, 0, + ptr::null_mut(), + ptr::null_mut(), + libloaderapi::GetModuleHandleW(ptr::null()), + ptr::null_mut() + ); + + let (tx, rx) = crossbeam_channel::unbounded(); + + let subclass_input = ThreadMsgTargetSubclassInput { + event_loop_runner, + user_event_receiver: rx + }; + let input_ptr = Box::into_raw(Box::new(subclass_input)); + let subclass_result = commctrl::SetWindowSubclass( + window, + Some(thread_event_target_callback::), + THREAD_EVENT_TARGET_SUBCLASS_ID, + input_ptr as DWORD_PTR + ); + assert_eq!(subclass_result, 1); + + (window, tx) + } } /// Capture mouse input, allowing `window` to receive mouse events when the cursor is outside of @@ -461,11 +667,12 @@ unsafe fn release_mouse(window_state: &mut WindowState) { } const WINDOW_SUBCLASS_ID: UINT_PTR = 0; -pub(crate) fn subclass_window(window: HWND, subclass_input: SubclassInput) { +const THREAD_EVENT_TARGET_SUBCLASS_ID: UINT_PTR = 1; +pub(crate) fn subclass_window(window: HWND, subclass_input: SubclassInput) { let input_ptr = Box::into_raw(Box::new(subclass_input)); let subclass_result = unsafe{ commctrl::SetWindowSubclass( window, - Some(callback), + Some(public_window_callback::), WINDOW_SUBCLASS_ID, input_ptr as DWORD_PTR ) }; @@ -479,7 +686,7 @@ pub(crate) fn subclass_window(window: HWND, subclass_input: SubclassInput) { // // Returning 0 tells the Win32 API that the message has been processed. // FIXME: detect WM_DWMCOMPOSITIONCHANGED and call DwmEnableBlurBehindWindow if necessary -pub unsafe extern "system" fn callback( +unsafe extern "system" fn public_window_callback( window: HWND, msg: UINT, wparam: WPARAM, @@ -487,9 +694,70 @@ pub unsafe extern "system" fn callback( _: UINT_PTR, subclass_input_ptr: DWORD_PTR ) -> LRESULT { - let subclass_input = &mut*(subclass_input_ptr as *mut SubclassInput); + let subclass_input = &mut*(subclass_input_ptr as *mut SubclassInput); match msg { + winuser::WM_SYSCOMMAND => { + { + let mut window_state = subclass_input.window_state.lock(); + if window_state.modal_timer_handle == 0 { + window_state.modal_timer_handle = winuser::SetTimer(window, 0, 0x7FFFFFFF, None); + } + } + commctrl::DefSubclassProc(window, msg, wparam, lparam) + } + winuser::WM_ENTERSIZEMOVE => { + let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle; + if let Some(runner) = *subclass_input.event_loop_runner.borrow_mut() { + (*runner).modal_loop_data = Some(ModalLoopData { + hwnd: window, + timer_handle: modal_timer_handle + }); + } + winuser::SetTimer(window, modal_timer_handle, 0, None); + 0 + }, + winuser::WM_EXITSIZEMOVE => { + let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle; + if let Some(runner) = *subclass_input.event_loop_runner.borrow_mut() { + (*runner).modal_loop_data = None; + } + winuser::SetTimer(window, modal_timer_handle, 0x7FFFFFFF, None); + 0 + }, + winuser::WM_TIMER => { + let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle; + if wparam == modal_timer_handle { + let runner = subclass_input.event_loop_runner.borrow_mut(); + if let Some(runner) = *runner { + let runner = &mut *runner; + if runner.modal_loop_data.is_some() { + runner.events_cleared(); + match runner.control_flow { + ControlFlow::Exit => (), + ControlFlow::Wait => { + winuser::SetTimer(window, modal_timer_handle, 0x7FFFFFFF, None); + }, + ControlFlow::WaitUntil(resume_time) => { + let now = Instant::now(); + let duration = match now <= resume_time { + true => dur2timeout(resume_time - now), + false => 0 + }; + winuser::SetTimer(window, modal_timer_handle, duration, None); + }, + ControlFlow::Poll => { + winuser::SetTimer(window, modal_timer_handle, 0, None); + } + } + + runner.new_events(); + } + } + } + 0 + } + winuser::WM_NCCREATE => { enable_non_client_dpi_scaling(window); commctrl::DefSubclassProc(window, msg, wparam, lparam) @@ -507,6 +775,12 @@ pub unsafe extern "system" fn callback( winuser::WM_DESTROY => { use events::WindowEvent::Destroyed; ole2::RevokeDragDrop(window); + { + let window_state = subclass_input.window_state.lock(); + if window_state.modal_timer_handle != 0 { + winuser::KillTimer(window, window_state.modal_timer_handle); + } + } subclass_input.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), event: Destroyed @@ -1169,3 +1443,33 @@ pub unsafe extern "system" fn callback( } } } + +unsafe extern "system" fn thread_event_target_callback( + window: HWND, + msg: UINT, + wparam: WPARAM, + lparam: LPARAM, + _: UINT_PTR, + subclass_input_ptr: DWORD_PTR +) -> LRESULT { + let subclass_input = &mut*(subclass_input_ptr as *mut ThreadMsgTargetSubclassInput); + match msg { + winuser::WM_DESTROY => { + Box::from_raw(subclass_input); + drop(subclass_input); + 0 + }, + _ if msg == *USER_EVENT_MSG_ID => { + if let Ok(event) = subclass_input.user_event_receiver.recv() { + subclass_input.send_event(Event::UserEvent(event)); + } + 0 + } + _ if msg == *EXEC_MSG_ID => { + let mut function: Box> = Box::from_raw(wparam as usize as *mut _); + function(); + 0 + } + _ => commctrl::DefSubclassProc(window, msg, wparam, lparam) + } +} diff --git a/src/platform/windows/window.rs b/src/platform/windows/window.rs index 547e4371a1..bf4a37b476 100644 --- a/src/platform/windows/window.rs +++ b/src/platform/windows/window.rs @@ -75,7 +75,7 @@ unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> B impl Window { pub fn new( - events_loop: &EventLoop, + event_loop: &EventLoop, w_attr: WindowAttributes, pl_attr: PlatformSpecificWindowBuilderAttributes, ) -> Result { @@ -83,7 +83,37 @@ impl Window { // First person to remove the need for cloning here gets a cookie! // // done. you owe me -- ossi - unsafe { init(w_attr, pl_attr, events_loop) } + unsafe { + init(w_attr, pl_attr, event_loop).map(|win| { + let file_drop_handler = { + use winapi::shared::winerror::{OLE_E_WRONGCOMPOBJ, RPC_E_CHANGED_MODE, S_OK}; + + let ole_init_result = ole2::OleInitialize(ptr::null_mut()); + // It is ok if the initialize result is `S_FALSE` because it might happen that + // multiple windows are created on the same thread. + if ole_init_result == OLE_E_WRONGCOMPOBJ { + panic!("OleInitialize failed! Result was: `OLE_E_WRONGCOMPOBJ`"); + } else if ole_init_result == RPC_E_CHANGED_MODE { + panic!("OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`"); + } + + let file_drop_handler = FileDropHandler::new(win.window.0/*, event_loop.event_send.clone()*/); + let handler_interface_ptr = &mut (*file_drop_handler.data).interface as LPDROPTARGET; + + assert_eq!(ole2::RegisterDragDrop(win.window.0, handler_interface_ptr), S_OK); + file_drop_handler + }; + + let subclass_input = events_loop::SubclassInput { + window_state: win.window_state.clone(), + event_loop_runner: event_loop.runner_shared.clone(), + file_drop_handler, + }; + + events_loop::subclass_window(win.window.0, subclass_input); + win + }) + } } pub fn set_title(&self, text: &str) { @@ -1004,22 +1034,24 @@ unsafe fn init( let min_size = attributes.min_dimensions .map(|logical_size| PhysicalSize::from_logical(logical_size, dpi_factor)); let mut window_state = events_loop::WindowState { - cursor: Cursor(winuser::IDC_ARROW), // use arrow by default - cursor_grabbed: false, - cursor_hidden: false, max_size, min_size, - mouse_in_window: false, - saved_window_info: None, dpi_factor, - fullscreen: attributes.fullscreen.clone(), window_icon, taskbar_icon, + fullscreen: attributes.fullscreen.clone(), decorations: attributes.decorations, maximized: attributes.maximized, resizable: attributes.resizable, always_on_top: attributes.always_on_top, - mouse_buttons_down: 0 + + cursor: Cursor(winuser::IDC_ARROW), // use arrow by default + cursor_grabbed: false, + cursor_hidden: false, + mouse_in_window: false, + saved_window_info: None, + mouse_buttons_down: 0, + modal_timer_handle: 0 }; // Creating a mutex to track the current window state Arc::new(Mutex::new(window_state)) @@ -1064,33 +1096,6 @@ unsafe fn init( force_window_active(win.window.0); } - let file_drop_handler = { - use winapi::shared::winerror::{OLE_E_WRONGCOMPOBJ, RPC_E_CHANGED_MODE, S_OK}; - - let ole_init_result = ole2::OleInitialize(ptr::null_mut()); - // It is ok if the initialize result is `S_FALSE` because it might happen that - // multiple windows are created on the same thread. - if ole_init_result == OLE_E_WRONGCOMPOBJ { - panic!("OleInitialize failed! Result was: `OLE_E_WRONGCOMPOBJ`"); - } else if ole_init_result == RPC_E_CHANGED_MODE { - panic!("OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`"); - } - - let file_drop_handler = FileDropHandler::new(win.window.0, event_loop.event_send.clone()); - let handler_interface_ptr = &mut (*file_drop_handler.data).interface as LPDROPTARGET; - - assert_eq!(ole2::RegisterDragDrop(win.window.0, handler_interface_ptr), S_OK); - file_drop_handler - }; - - let subclass_input = events_loop::SubclassInput { - window_state: win.window_state.clone(), - event_send: event_loop.event_send.clone(), - file_drop_handler, - }; - - events_loop::subclass_window(win.window.0, subclass_input); - Ok(win) } From 99c0f84a9fc771c9c96099232de3716ddf27ca80 Mon Sep 17 00:00:00 2001 From: Osspial Date: Wed, 22 Aug 2018 17:55:27 -0400 Subject: [PATCH 10/40] Add request_redraw --- examples/request_redraw.rs | 28 ++++++ src/events.rs | 4 +- src/platform/windows/events_loop.rs | 129 ++++++++++++++++++++-------- src/platform/windows/window.rs | 19 +++- src/window.rs | 15 ++++ 5 files changed, 157 insertions(+), 38 deletions(-) create mode 100644 examples/request_redraw.rs diff --git a/examples/request_redraw.rs b/examples/request_redraw.rs new file mode 100644 index 0000000000..a870fb8df0 --- /dev/null +++ b/examples/request_redraw.rs @@ -0,0 +1,28 @@ +extern crate winit; +use winit::{Event, WindowEvent}; +use std::time::{Instant, Duration}; + +fn main() { + let events_loop = winit::EventLoop::new(); + + let window = winit::WindowBuilder::new() + .with_title("A fantastic window!") + .build(&events_loop) + .unwrap(); + + events_loop.run(move |event, _, control_flow| { + println!("{:?}", event); + + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = winit::ControlFlow::Exit, + Event::EventsCleared => { + window.request_redraw(); + *control_flow = winit::ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0)) + }, + _ => () + } + }); +} diff --git a/src/events.rs b/src/events.rs index 407afdfe45..dab2d7d06e 100644 --- a/src/events.rs +++ b/src/events.rs @@ -140,8 +140,8 @@ pub enum WindowEvent { /// Motion on some analog axis. May report data redundant to other, more specific events. AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 }, - /// The window needs to be redrawn. - Redraw, + /// The OS or application has requested that the window be redrawn. + RedrawRequested, /// Touch event has been received Touch(Touch), diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index c8a1c6b3ab..ee74dc35a4 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -16,6 +16,7 @@ use winapi::shared::basetsd::DWORD_PTR; use winapi::shared::basetsd::UINT_PTR; use std::{mem, ptr}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use std::rc::Rc; use std::cell::RefCell; @@ -129,11 +130,10 @@ pub(crate) struct SubclassInput { impl SubclassInput { unsafe fn send_event(&self, event: Event) { - let runner = self.event_loop_runner.borrow_mut(); - if let Some(runner) = *runner { - (*runner).process_event(event); - } else { - panic!("Attempted to send event without active runner"); + let mut runner = self.event_loop_runner.borrow_mut(); + match *runner { + ELRSharedOption::Runner(runner) => (*runner).process_event(event), + ELRSharedOption::Buffer(ref mut buffer) => buffer.push(event) } } } @@ -145,11 +145,10 @@ struct ThreadMsgTargetSubclassInput { impl ThreadMsgTargetSubclassInput { unsafe fn send_event(&self, event: Event) { - let runner = self.event_loop_runner.borrow_mut(); - if let Some(runner) = *runner { - (*runner).process_event(event); - } else { - panic!("Attempted to send event without active runner"); + let mut runner = self.event_loop_runner.borrow_mut(); + match *runner { + ELRSharedOption::Runner(runner) => (*runner).process_event(event), + ELRSharedOption::Buffer(ref mut buffer) => buffer.push(event) } } } @@ -159,6 +158,7 @@ pub struct EventLoop { thread_id: DWORD, thread_msg_target: HWND, thread_msg_sender: Sender, + trigger_newevents_on_redraw: Arc, pub(crate) runner_shared: EventLoopRunnerShared, } @@ -171,12 +171,13 @@ impl EventLoop { become_dpi_aware(dpi_aware); let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; - let runner_shared = Rc::new(RefCell::new(None)); + let runner_shared = Rc::new(RefCell::new(ELRSharedOption::Buffer(vec![]))); let (thread_msg_target, thread_msg_sender) = thread_event_target_window(runner_shared.clone()); EventLoop { thread_id, thread_msg_target, thread_msg_sender, + trigger_newevents_on_redraw: Arc::new(AtomicBool::new(true)), runner_shared } } @@ -197,7 +198,19 @@ impl EventLoop { modal_loop_data: None, event_handler: &mut event_handler }; - *runner.event_loop.events_loop.runner_shared.borrow_mut() = Some(&mut runner); + { + let runner_shared = runner.event_loop.events_loop.runner_shared.clone(); + let mut runner_shared = runner_shared.borrow_mut(); + let mut event_buffer = vec![]; + if let ELRSharedOption::Buffer(ref mut buffer) = *runner_shared { + mem::swap(buffer, &mut event_buffer); + } + for event in event_buffer.drain(..) { + runner.process_event(event); + } + *runner_shared = ELRSharedOption::Runner(&mut runner); + } + let timer_handle = winuser::SetTimer(ptr::null_mut(), 0, 0x7FFFFFFF, None); let mut msg = mem::uninitialized(); @@ -242,7 +255,7 @@ impl EventLoop { } runner.call_event_handler(Event::LoopDestroyed); - *runner.event_loop.events_loop.runner_shared.borrow_mut() = None; + *runner.event_loop.events_loop.runner_shared.borrow_mut() = ELRSharedOption::Buffer(vec![]); } drop(event_handler); @@ -259,12 +272,17 @@ impl EventLoop { #[inline(always)] pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor { EventLoopThreadExecutor { - thread_id: self.thread_id + thread_id: self.thread_id, + trigger_newevents_on_redraw: self.trigger_newevents_on_redraw.clone() } } } -pub(crate) type EventLoopRunnerShared = Rc>>>; +pub(crate) type EventLoopRunnerShared = Rc>>; +pub(crate) enum ELRSharedOption { + Runner(*mut EventLoopRunner), + Buffer(Vec>) +} pub(crate) struct EventLoopRunner { event_loop: ::EventLoop, control_flow: ControlFlow, @@ -346,8 +364,10 @@ impl EventLoopRunner { } unsafe fn process_event(&mut self, event: Event) { + // If we're in the middle of a modal loop, only set the timer for zero if it hasn't been + // reset in a prior call to `process_event`. if let Some(ModalLoopData{hwnd, timer_handle}) = self.modal_loop_data { - if !self.event_processing_active() { + if self.runner_state != RunnerState::HandlingEvents { winuser::SetTimer(hwnd, timer_handle, 0, None); } } @@ -385,10 +405,9 @@ impl EventLoopRunner { ControlFlow::Poll | ControlFlow::Exit => unreachable!() } - - self.runner_state = RunnerState::HandlingEvents; } + self.runner_state = RunnerState::HandlingEvents; self.call_event_handler(event); } @@ -437,6 +456,12 @@ impl EventLoopRunner { unsafe fn call_event_handler(&mut self, event: Event) { if self.event_handler != mem::zeroed() { + match event { + Event::NewEvents(_) => self.event_loop.events_loop.trigger_newevents_on_redraw.store(true, Ordering::Relaxed), + Event::EventsCleared => self.event_loop.events_loop.trigger_newevents_on_redraw.store(false, Ordering::Relaxed), + _ => () + } + if self.control_flow != ControlFlow::Exit { (*self.event_handler)(event, &self.event_loop, &mut self.control_flow); } else { @@ -446,15 +471,6 @@ impl EventLoopRunner { panic!("Tried to call event handler with null handler"); } } - - fn event_processing_active(&self) -> bool { - match self.runner_state { - RunnerState::HandlingEvents => true, - RunnerState::DeferredNewEvents(..) | - RunnerState::New | - RunnerState::Idle(..) => false - } - } } // Implementation taken from https://github.com/rust-lang/rust/blob/db5476571d9b27c862b95c1e64764b0ac8980e23/src/libstd/sys/windows/mod.rs @@ -490,7 +506,8 @@ impl Drop for EventLoop { } pub(crate) struct EventLoopThreadExecutor { - thread_id: DWORD + thread_id: DWORD, + trigger_newevents_on_redraw: Arc } impl EventLoopThreadExecutor { @@ -500,6 +517,10 @@ impl EventLoopThreadExecutor { self.thread_id == cur_thread_id } + pub(super) fn trigger_newevents_on_redraw(&self) -> bool { + !self.in_event_loop_thread() || self.trigger_newevents_on_redraw.load(Ordering::Relaxed) + } + /// Executes a function in the event loop thread. If we're already in the event loop thread, /// we just call the function directly. /// @@ -586,6 +607,12 @@ lazy_static! { winuser::RegisterWindowMessageA("Winit::InitialDpiMsg\0".as_ptr() as LPCSTR) } }; + // Message sent by a `Window` if it's requesting a redraw without sending a NewEvents. + pub static ref REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID: u32 = { + unsafe { + winuser::RegisterWindowMessageA("Winit::RequestRedrawNoNewevents\0".as_ptr() as LPCSTR) + } + }; static ref THREAD_EVENT_TARGET_WINDOW_CLASS: Vec = unsafe { use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; @@ -708,7 +735,7 @@ unsafe extern "system" fn public_window_callback( } winuser::WM_ENTERSIZEMOVE => { let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle; - if let Some(runner) = *subclass_input.event_loop_runner.borrow_mut() { + if let ELRSharedOption::Runner(runner) = *subclass_input.event_loop_runner.borrow_mut() { (*runner).modal_loop_data = Some(ModalLoopData { hwnd: window, timer_handle: modal_timer_handle @@ -719,7 +746,7 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_EXITSIZEMOVE => { let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle; - if let Some(runner) = *subclass_input.event_loop_runner.borrow_mut() { + if let ELRSharedOption::Runner(runner) = *subclass_input.event_loop_runner.borrow_mut() { (*runner).modal_loop_data = None; } winuser::SetTimer(window, modal_timer_handle, 0x7FFFFFFF, None); @@ -729,7 +756,7 @@ unsafe extern "system" fn public_window_callback( let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle; if wparam == modal_timer_handle { let runner = subclass_input.event_loop_runner.borrow_mut(); - if let Some(runner) = *runner { + if let ELRSharedOption::Runner(runner) = *runner { let runner = &mut *runner; if runner.modal_loop_data.is_some() { runner.events_cleared(); @@ -791,12 +818,44 @@ unsafe extern "system" fn public_window_callback( 0 }, + _ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => { + use events::WindowEvent::RedrawRequested; + let runner = subclass_input.event_loop_runner.borrow_mut(); + if let ELRSharedOption::Runner(runner) = *runner { + let runner = &mut *runner; + match runner.runner_state { + RunnerState::Idle(..) | + RunnerState::DeferredNewEvents(..) => runner.call_event_handler(Event::WindowEvent { + window_id: SuperWindowId(WindowId(window)), + event: RedrawRequested, + }), + _ => () + } + } + 0 + }, winuser::WM_PAINT => { - use events::WindowEvent::Redraw; - subclass_input.send_event(Event::WindowEvent { + use events::WindowEvent::RedrawRequested; + let event = || Event::WindowEvent { window_id: SuperWindowId(WindowId(window)), - event: Redraw, - }); + event: RedrawRequested, + }; + + let mut send_event = false; + { + let runner = subclass_input.event_loop_runner.borrow_mut(); + if let ELRSharedOption::Runner(runner) = *runner { + let runner = &mut *runner; + match runner.runner_state { + RunnerState::Idle(..) | + RunnerState::DeferredNewEvents(..) => runner.call_event_handler(event()), + _ => send_event = true + } + } + } + if send_event { + subclass_input.send_event(event()); + } commctrl::DefSubclassProc(window, msg, wparam, lparam) }, diff --git a/src/platform/windows/window.rs b/src/platform/windows/window.rs index bf4a37b476..ed66252f05 100644 --- a/src/platform/windows/window.rs +++ b/src/platform/windows/window.rs @@ -30,7 +30,8 @@ use { }; use platform::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, WindowId}; use platform::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi}; -use platform::platform::events_loop::{self, DESTROY_MSG_ID, EventLoop, INITIAL_DPI_MSG_ID, WindowState}; +use platform::platform::events_loop::{self, EventLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}; +use platform::platform::events_loop::WindowState; use platform::platform::icon::{self, IconType, WinIcon}; use platform::platform::monitor; use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input; @@ -140,6 +141,22 @@ impl Window { } } + #[inline] + pub fn request_redraw(&self) { + unsafe { + if self.thread_executor.trigger_newevents_on_redraw() { + winuser::RedrawWindow( + self.window.0, + ptr::null(), + ptr::null_mut(), + winuser::RDW_INTERNALPAINT + ); + } else { + winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0); + } + } + } + pub(crate) fn get_position_physical(&self) -> Option<(i32, i32)> { util::get_window_rect(self.window.0) .map(|rect| (rect.left as i32, rect.top as i32)) diff --git a/src/window.rs b/src/window.rs index 6468099fd3..0abba65f14 100644 --- a/src/window.rs +++ b/src/window.rs @@ -205,6 +205,21 @@ impl Window { self.window.hide() } + /// Emits a `WindowEvent::RedrawRequested` event in the associated event loop after all OS + /// events have been processed by the event loop. + /// + /// This is the **strongly encouraged** method of redrawing windows, as it can integrates with + /// OS-requested redraws (e.g. when a window gets resized). + /// + /// This function can cause `RedrawRequested` events to be emitted after `Event::EventsCleared` + /// but before `Event::NewEvents` if called in the following circumstances: + /// * While processing `EventsCleared`. + /// * While processing a `RedrawRequested` event that was sent during `EventsCleared` or any + /// directly subsequent `RedrawRequested` event. + pub fn request_redraw(&self) { + self.window.request_redraw() + } + /// Returns the position of the top-left hand corner of the window relative to the /// top-left hand corner of the desktop. /// From 7df59c60a06008226f6455619e7242ed0156ed8d Mon Sep 17 00:00:00 2001 From: Osspial Date: Wed, 22 Aug 2018 17:59:36 -0400 Subject: [PATCH 11/40] Rename platform to platform_impl --- src/lib.rs | 16 ++++++++-------- src/os/unix.rs | 12 ++++++------ src/os/windows.rs | 2 +- src/{platform => platform_impl}/android/ffi.rs | 0 src/{platform => platform_impl}/android/mod.rs | 0 .../emscripten/ffi.rs | 0 .../emscripten/mod.rs | 0 src/{platform => platform_impl}/ios/ffi.rs | 0 src/{platform => platform_impl}/ios/mod.rs | 0 .../linux/dlopen.rs | 0 src/{platform => platform_impl}/linux/mod.rs | 0 .../linux/wayland/event_loop.rs | 0 .../linux/wayland/keyboard.rs | 0 .../linux/wayland/mod.rs | 0 .../linux/wayland/pointer.rs | 0 .../linux/wayland/touch.rs | 0 .../linux/wayland/window.rs | 4 ++-- .../linux/x11/dnd.rs | 0 .../linux/x11/events.rs | 0 .../linux/x11/ffi.rs | 0 .../linux/x11/ime/callbacks.rs | 0 .../linux/x11/ime/context.rs | 0 .../linux/x11/ime/inner.rs | 0 .../linux/x11/ime/input_method.rs | 0 .../linux/x11/ime/mod.rs | 0 .../linux/x11/mod.rs | 2 +- .../linux/x11/monitor.rs | 0 .../linux/x11/util/atom.rs | 0 .../linux/x11/util/client_msg.rs | 0 .../linux/x11/util/format.rs | 0 .../linux/x11/util/geometry.rs | 0 .../linux/x11/util/hint.rs | 0 .../linux/x11/util/icon.rs | 0 .../linux/x11/util/input.rs | 0 .../linux/x11/util/memory.rs | 0 .../linux/x11/util/mod.rs | 0 .../linux/x11/util/randr.rs | 0 .../linux/x11/util/window_property.rs | 0 .../linux/x11/util/wm.rs | 0 .../linux/x11/window.rs | 6 +++--- .../linux/x11/xdisplay.rs | 0 .../macos/events_loop.rs | 0 src/{platform => platform_impl}/macos/ffi.rs | 0 src/{platform => platform_impl}/macos/mod.rs | 0 .../macos/monitor.rs | 0 src/{platform => platform_impl}/macos/util.rs | 4 ++-- src/{platform => platform_impl}/macos/view.rs | 8 ++++---- .../macos/window.rs | 6 +++--- src/{platform => platform_impl}/mod.rs | 0 src/{platform => platform_impl}/windows/dpi.rs | 0 .../windows/drop_handler.rs | 2 +- .../windows/event.rs | 0 .../windows/events_loop.rs | 14 +++++++------- .../windows/icon.rs | 2 +- src/{platform => platform_impl}/windows/mod.rs | 0 .../windows/monitor.rs | 4 ++-- .../windows/raw_input.rs | 2 +- .../windows/util.rs | 0 .../windows/window.rs | 18 +++++++++--------- src/window.rs | 8 ++++---- 60 files changed, 55 insertions(+), 55 deletions(-) rename src/{platform => platform_impl}/android/ffi.rs (100%) rename src/{platform => platform_impl}/android/mod.rs (100%) rename src/{platform => platform_impl}/emscripten/ffi.rs (100%) rename src/{platform => platform_impl}/emscripten/mod.rs (100%) rename src/{platform => platform_impl}/ios/ffi.rs (100%) rename src/{platform => platform_impl}/ios/mod.rs (100%) rename src/{platform => platform_impl}/linux/dlopen.rs (100%) rename src/{platform => platform_impl}/linux/mod.rs (100%) rename src/{platform => platform_impl}/linux/wayland/event_loop.rs (100%) rename src/{platform => platform_impl}/linux/wayland/keyboard.rs (100%) rename src/{platform => platform_impl}/linux/wayland/mod.rs (100%) rename src/{platform => platform_impl}/linux/wayland/pointer.rs (100%) rename src/{platform => platform_impl}/linux/wayland/touch.rs (100%) rename src/{platform => platform_impl}/linux/wayland/window.rs (98%) rename src/{platform => platform_impl}/linux/x11/dnd.rs (100%) rename src/{platform => platform_impl}/linux/x11/events.rs (100%) rename src/{platform => platform_impl}/linux/x11/ffi.rs (100%) rename src/{platform => platform_impl}/linux/x11/ime/callbacks.rs (100%) rename src/{platform => platform_impl}/linux/x11/ime/context.rs (100%) rename src/{platform => platform_impl}/linux/x11/ime/inner.rs (100%) rename src/{platform => platform_impl}/linux/x11/ime/input_method.rs (100%) rename src/{platform => platform_impl}/linux/x11/ime/mod.rs (100%) rename src/{platform => platform_impl}/linux/x11/mod.rs (99%) rename src/{platform => platform_impl}/linux/x11/monitor.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/atom.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/client_msg.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/format.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/geometry.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/hint.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/icon.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/input.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/memory.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/mod.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/randr.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/window_property.rs (100%) rename src/{platform => platform_impl}/linux/x11/util/wm.rs (100%) rename src/{platform => platform_impl}/linux/x11/window.rs (99%) rename src/{platform => platform_impl}/linux/x11/xdisplay.rs (100%) rename src/{platform => platform_impl}/macos/events_loop.rs (100%) rename src/{platform => platform_impl}/macos/ffi.rs (100%) rename src/{platform => platform_impl}/macos/mod.rs (100%) rename src/{platform => platform_impl}/macos/monitor.rs (100%) rename src/{platform => platform_impl}/macos/util.rs (94%) rename src/{platform => platform_impl}/macos/view.rs (98%) rename src/{platform => platform_impl}/macos/window.rs (99%) rename src/{platform => platform_impl}/mod.rs (100%) rename src/{platform => platform_impl}/windows/dpi.rs (100%) rename src/{platform => platform_impl}/windows/drop_handler.rs (99%) rename src/{platform => platform_impl}/windows/event.rs (100%) rename src/{platform => platform_impl}/windows/events_loop.rs (99%) rename src/{platform => platform_impl}/windows/icon.rs (98%) rename src/{platform => platform_impl}/windows/mod.rs (100%) rename src/{platform => platform_impl}/windows/monitor.rs (97%) rename src/{platform => platform_impl}/windows/raw_input.rs (99%) rename src/{platform => platform_impl}/windows/util.rs (100%) rename src/{platform => platform_impl}/windows/window.rs (98%) diff --git a/src/lib.rs b/src/lib.rs index 3b7a1fc161..c5378a3ec1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,7 +102,7 @@ pub use icon::*; pub mod dpi; mod events; mod icon; -mod platform; +mod platform_impl; mod window; pub mod os; @@ -127,7 +127,7 @@ pub mod os; /// }); /// ``` pub struct Window { - window: platform::Window, + window: platform_impl::Window, } impl std::fmt::Debug for Window { @@ -143,7 +143,7 @@ impl std::fmt::Debug for Window { /// Whenever you receive an event specific to a window, this event contains a `WindowId` which you /// can then compare to the ids of your windows. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct WindowId(platform::WindowId); +pub struct WindowId(platform_impl::WindowId); /// Identifier of an input device. /// @@ -151,7 +151,7 @@ pub struct WindowId(platform::WindowId); /// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or /// physical. Virtual devices typically aggregate inputs from multiple physical devices. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct DeviceId(platform::DeviceId); +pub struct DeviceId(platform_impl::DeviceId); /// Provides a way to retrieve events from the system and from the windows that were registered to /// the events loop. @@ -167,7 +167,7 @@ pub struct DeviceId(platform::DeviceId); /// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the /// `EventLoopProxy` allows you to wakeup an `EventLoop` from an other thread. pub struct EventLoop { - events_loop: platform::EventLoop, + events_loop: platform_impl::EventLoop, _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync } @@ -217,7 +217,7 @@ impl EventLoop { /// fallback on x11. If this variable is set with any other value, winit will panic. pub fn new_user_event() -> EventLoop { EventLoop { - events_loop: platform::EventLoop::new(), + events_loop: platform_impl::EventLoop::new(), _marker: ::std::marker::PhantomData, } } @@ -260,7 +260,7 @@ impl EventLoop { /// Used to wake up the `EventLoop` from another thread. #[derive(Clone)] pub struct EventLoopProxy { - events_loop_proxy: platform::EventLoopProxy, + events_loop_proxy: platform_impl::EventLoopProxy, } impl std::fmt::Debug for EventLoopProxy { @@ -304,7 +304,7 @@ pub struct WindowBuilder { pub window: WindowAttributes, // Platform-specific configuration. Private. - platform_specific: platform::PlatformSpecificWindowBuilderAttributes, + platform_specific: platform_impl::PlatformSpecificWindowBuilderAttributes, } impl std::fmt::Debug for WindowBuilder { diff --git a/src/os/unix.rs b/src/os/unix.rs index 9c2e446707..7b2640030a 100644 --- a/src/os/unix.rs +++ b/src/os/unix.rs @@ -11,19 +11,19 @@ use { Window, WindowBuilder, }; -use platform::{ +use platform_impl::{ EventLoop as LinuxEventLoop, Window as LinuxWindow, }; -use platform::x11::XConnection; -use platform::x11::ffi::XVisualInfo; +use platform_impl::x11::XConnection; +use platform_impl::x11::ffi::XVisualInfo; // TODO: stupid hack so that glutin can do its work #[doc(hidden)] -pub use platform::x11; +pub use platform_impl::x11; -pub use platform::XNotSupported; -pub use platform::x11::util::WindowType as XWindowType; +pub use platform_impl::XNotSupported; +pub use platform_impl::x11::util::WindowType as XWindowType; /// Additional methods on `EventLoop` that are specific to Linux. pub trait EventLoopExt { diff --git a/src/os/windows.rs b/src/os/windows.rs index 6a5b67df1f..96a178041c 100644 --- a/src/os/windows.rs +++ b/src/os/windows.rs @@ -6,7 +6,7 @@ use libc; use winapi::shared::windef::HWND; use {DeviceId, EventLoop, Icon, MonitorId, Window, WindowBuilder}; -use platform::EventLoop as WindowsEventLoop; +use platform_impl::EventLoop as WindowsEventLoop; /// Additional methods on `EventLoop` that are specific to Windows. pub trait EventLoopExt { diff --git a/src/platform/android/ffi.rs b/src/platform_impl/android/ffi.rs similarity index 100% rename from src/platform/android/ffi.rs rename to src/platform_impl/android/ffi.rs diff --git a/src/platform/android/mod.rs b/src/platform_impl/android/mod.rs similarity index 100% rename from src/platform/android/mod.rs rename to src/platform_impl/android/mod.rs diff --git a/src/platform/emscripten/ffi.rs b/src/platform_impl/emscripten/ffi.rs similarity index 100% rename from src/platform/emscripten/ffi.rs rename to src/platform_impl/emscripten/ffi.rs diff --git a/src/platform/emscripten/mod.rs b/src/platform_impl/emscripten/mod.rs similarity index 100% rename from src/platform/emscripten/mod.rs rename to src/platform_impl/emscripten/mod.rs diff --git a/src/platform/ios/ffi.rs b/src/platform_impl/ios/ffi.rs similarity index 100% rename from src/platform/ios/ffi.rs rename to src/platform_impl/ios/ffi.rs diff --git a/src/platform/ios/mod.rs b/src/platform_impl/ios/mod.rs similarity index 100% rename from src/platform/ios/mod.rs rename to src/platform_impl/ios/mod.rs diff --git a/src/platform/linux/dlopen.rs b/src/platform_impl/linux/dlopen.rs similarity index 100% rename from src/platform/linux/dlopen.rs rename to src/platform_impl/linux/dlopen.rs diff --git a/src/platform/linux/mod.rs b/src/platform_impl/linux/mod.rs similarity index 100% rename from src/platform/linux/mod.rs rename to src/platform_impl/linux/mod.rs diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs similarity index 100% rename from src/platform/linux/wayland/event_loop.rs rename to src/platform_impl/linux/wayland/event_loop.rs diff --git a/src/platform/linux/wayland/keyboard.rs b/src/platform_impl/linux/wayland/keyboard.rs similarity index 100% rename from src/platform/linux/wayland/keyboard.rs rename to src/platform_impl/linux/wayland/keyboard.rs diff --git a/src/platform/linux/wayland/mod.rs b/src/platform_impl/linux/wayland/mod.rs similarity index 100% rename from src/platform/linux/wayland/mod.rs rename to src/platform_impl/linux/wayland/mod.rs diff --git a/src/platform/linux/wayland/pointer.rs b/src/platform_impl/linux/wayland/pointer.rs similarity index 100% rename from src/platform/linux/wayland/pointer.rs rename to src/platform_impl/linux/wayland/pointer.rs diff --git a/src/platform/linux/wayland/touch.rs b/src/platform_impl/linux/wayland/touch.rs similarity index 100% rename from src/platform/linux/wayland/touch.rs rename to src/platform_impl/linux/wayland/touch.rs diff --git a/src/platform/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs similarity index 98% rename from src/platform/linux/wayland/window.rs rename to src/platform_impl/linux/wayland/window.rs index 42b7c52b83..b0f28359b9 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex, Weak}; use {CreationError, MouseCursor, WindowAttributes}; use dpi::{LogicalPosition, LogicalSize}; -use platform::MonitorId as PlatformMonitorId; +use platform_impl::MonitorId as PlatformMonitorId; use window::MonitorId as RootMonitorId; use sctk::window::{ConceptFrame, Event as WEvent, Window as SWindow}; @@ -14,7 +14,7 @@ use sctk::reexports::client::protocol::wl_surface::RequestsTrait as SurfaceReque use sctk::output::OutputMgr; use super::{make_wid, EventLoop, MonitorId, WindowId}; -use platform::platform::wayland::event_loop::{get_available_monitors, get_primary_monitor}; +use platform_impl::platform::wayland::event_loop::{get_available_monitors, get_primary_monitor}; pub struct Window { surface: Proxy, diff --git a/src/platform/linux/x11/dnd.rs b/src/platform_impl/linux/x11/dnd.rs similarity index 100% rename from src/platform/linux/x11/dnd.rs rename to src/platform_impl/linux/x11/dnd.rs diff --git a/src/platform/linux/x11/events.rs b/src/platform_impl/linux/x11/events.rs similarity index 100% rename from src/platform/linux/x11/events.rs rename to src/platform_impl/linux/x11/events.rs diff --git a/src/platform/linux/x11/ffi.rs b/src/platform_impl/linux/x11/ffi.rs similarity index 100% rename from src/platform/linux/x11/ffi.rs rename to src/platform_impl/linux/x11/ffi.rs diff --git a/src/platform/linux/x11/ime/callbacks.rs b/src/platform_impl/linux/x11/ime/callbacks.rs similarity index 100% rename from src/platform/linux/x11/ime/callbacks.rs rename to src/platform_impl/linux/x11/ime/callbacks.rs diff --git a/src/platform/linux/x11/ime/context.rs b/src/platform_impl/linux/x11/ime/context.rs similarity index 100% rename from src/platform/linux/x11/ime/context.rs rename to src/platform_impl/linux/x11/ime/context.rs diff --git a/src/platform/linux/x11/ime/inner.rs b/src/platform_impl/linux/x11/ime/inner.rs similarity index 100% rename from src/platform/linux/x11/ime/inner.rs rename to src/platform_impl/linux/x11/ime/inner.rs diff --git a/src/platform/linux/x11/ime/input_method.rs b/src/platform_impl/linux/x11/ime/input_method.rs similarity index 100% rename from src/platform/linux/x11/ime/input_method.rs rename to src/platform_impl/linux/x11/ime/input_method.rs diff --git a/src/platform/linux/x11/ime/mod.rs b/src/platform_impl/linux/x11/ime/mod.rs similarity index 100% rename from src/platform/linux/x11/ime/mod.rs rename to src/platform_impl/linux/x11/ime/mod.rs diff --git a/src/platform/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs similarity index 99% rename from src/platform/linux/x11/mod.rs rename to src/platform_impl/linux/x11/mod.rs index d1ff7a63c0..e87439e2f2 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -37,7 +37,7 @@ use { WindowEvent, }; use events::ModifiersState; -use platform::PlatformSpecificWindowBuilderAttributes; +use platform_impl::PlatformSpecificWindowBuilderAttributes; use self::dnd::{Dnd, DndState}; use self::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime}; diff --git a/src/platform/linux/x11/monitor.rs b/src/platform_impl/linux/x11/monitor.rs similarity index 100% rename from src/platform/linux/x11/monitor.rs rename to src/platform_impl/linux/x11/monitor.rs diff --git a/src/platform/linux/x11/util/atom.rs b/src/platform_impl/linux/x11/util/atom.rs similarity index 100% rename from src/platform/linux/x11/util/atom.rs rename to src/platform_impl/linux/x11/util/atom.rs diff --git a/src/platform/linux/x11/util/client_msg.rs b/src/platform_impl/linux/x11/util/client_msg.rs similarity index 100% rename from src/platform/linux/x11/util/client_msg.rs rename to src/platform_impl/linux/x11/util/client_msg.rs diff --git a/src/platform/linux/x11/util/format.rs b/src/platform_impl/linux/x11/util/format.rs similarity index 100% rename from src/platform/linux/x11/util/format.rs rename to src/platform_impl/linux/x11/util/format.rs diff --git a/src/platform/linux/x11/util/geometry.rs b/src/platform_impl/linux/x11/util/geometry.rs similarity index 100% rename from src/platform/linux/x11/util/geometry.rs rename to src/platform_impl/linux/x11/util/geometry.rs diff --git a/src/platform/linux/x11/util/hint.rs b/src/platform_impl/linux/x11/util/hint.rs similarity index 100% rename from src/platform/linux/x11/util/hint.rs rename to src/platform_impl/linux/x11/util/hint.rs diff --git a/src/platform/linux/x11/util/icon.rs b/src/platform_impl/linux/x11/util/icon.rs similarity index 100% rename from src/platform/linux/x11/util/icon.rs rename to src/platform_impl/linux/x11/util/icon.rs diff --git a/src/platform/linux/x11/util/input.rs b/src/platform_impl/linux/x11/util/input.rs similarity index 100% rename from src/platform/linux/x11/util/input.rs rename to src/platform_impl/linux/x11/util/input.rs diff --git a/src/platform/linux/x11/util/memory.rs b/src/platform_impl/linux/x11/util/memory.rs similarity index 100% rename from src/platform/linux/x11/util/memory.rs rename to src/platform_impl/linux/x11/util/memory.rs diff --git a/src/platform/linux/x11/util/mod.rs b/src/platform_impl/linux/x11/util/mod.rs similarity index 100% rename from src/platform/linux/x11/util/mod.rs rename to src/platform_impl/linux/x11/util/mod.rs diff --git a/src/platform/linux/x11/util/randr.rs b/src/platform_impl/linux/x11/util/randr.rs similarity index 100% rename from src/platform/linux/x11/util/randr.rs rename to src/platform_impl/linux/x11/util/randr.rs diff --git a/src/platform/linux/x11/util/window_property.rs b/src/platform_impl/linux/x11/util/window_property.rs similarity index 100% rename from src/platform/linux/x11/util/window_property.rs rename to src/platform_impl/linux/x11/util/window_property.rs diff --git a/src/platform/linux/x11/util/wm.rs b/src/platform_impl/linux/x11/util/wm.rs similarity index 100% rename from src/platform/linux/x11/util/wm.rs rename to src/platform_impl/linux/x11/util/wm.rs diff --git a/src/platform/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs similarity index 99% rename from src/platform/linux/x11/window.rs rename to src/platform_impl/linux/x11/window.rs index a2b83c0289..f37a55743e 100644 --- a/src/platform/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -10,9 +10,9 @@ use parking_lot::Mutex; use {Icon, MouseCursor, WindowAttributes}; use CreationError::{self, OsError}; use dpi::{LogicalPosition, LogicalSize}; -use platform::MonitorId as PlatformMonitorId; -use platform::PlatformSpecificWindowBuilderAttributes; -use platform::x11::MonitorId as X11MonitorId; +use platform_impl::MonitorId as PlatformMonitorId; +use platform_impl::PlatformSpecificWindowBuilderAttributes; +use platform_impl::x11::MonitorId as X11MonitorId; use window::MonitorId as RootMonitorId; use super::{ffi, util, ImeSender, XConnection, XError, WindowId, EventLoop}; diff --git a/src/platform/linux/x11/xdisplay.rs b/src/platform_impl/linux/x11/xdisplay.rs similarity index 100% rename from src/platform/linux/x11/xdisplay.rs rename to src/platform_impl/linux/x11/xdisplay.rs diff --git a/src/platform/macos/events_loop.rs b/src/platform_impl/macos/events_loop.rs similarity index 100% rename from src/platform/macos/events_loop.rs rename to src/platform_impl/macos/events_loop.rs diff --git a/src/platform/macos/ffi.rs b/src/platform_impl/macos/ffi.rs similarity index 100% rename from src/platform/macos/ffi.rs rename to src/platform_impl/macos/ffi.rs diff --git a/src/platform/macos/mod.rs b/src/platform_impl/macos/mod.rs similarity index 100% rename from src/platform/macos/mod.rs rename to src/platform_impl/macos/mod.rs diff --git a/src/platform/macos/monitor.rs b/src/platform_impl/macos/monitor.rs similarity index 100% rename from src/platform/macos/monitor.rs rename to src/platform_impl/macos/monitor.rs diff --git a/src/platform/macos/util.rs b/src/platform_impl/macos/util.rs similarity index 94% rename from src/platform/macos/util.rs rename to src/platform_impl/macos/util.rs index 2e5d6b49ac..c4c348f036 100644 --- a/src/platform/macos/util.rs +++ b/src/platform_impl/macos/util.rs @@ -3,8 +3,8 @@ use cocoa::base::{id, nil}; use cocoa::foundation::{NSRect, NSUInteger}; use core_graphics::display::CGDisplay; -use platform::platform::ffi; -use platform::platform::window::IdRef; +use platform_impl::platform::ffi; +use platform_impl::platform::window::IdRef; pub const EMPTY_RANGE: ffi::NSRange = ffi::NSRange { location: ffi::NSNotFound as NSUInteger, diff --git a/src/platform/macos/view.rs b/src/platform_impl/macos/view.rs similarity index 98% rename from src/platform/macos/view.rs rename to src/platform_impl/macos/view.rs index 64296aeb1c..6b82726454 100644 --- a/src/platform/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -14,10 +14,10 @@ use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Protocol, Sel, BOOL, YES}; use {ElementState, Event, KeyboardInput, MouseButton, WindowEvent, WindowId}; -use platform::platform::events_loop::{DEVICE_ID, event_mods, Shared, to_virtual_key_code, check_additional_virtual_key_codes}; -use platform::platform::util; -use platform::platform::ffi::*; -use platform::platform::window::{get_window_id, IdRef}; +use platform_impl::platform::events_loop::{DEVICE_ID, event_mods, Shared, to_virtual_key_code, check_additional_virtual_key_codes}; +use platform_impl::platform::util; +use platform_impl::platform::ffi::*; +use platform_impl::platform::window::{get_window_id, IdRef}; struct ViewState { window: id, diff --git a/src/platform/macos/window.rs b/src/platform_impl/macos/window.rs similarity index 99% rename from src/platform/macos/window.rs rename to src/platform_impl/macos/window.rs index 26b14b3e25..2ca3187b5f 100644 --- a/src/platform/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -41,9 +41,9 @@ use { }; use CreationError::OsError; use os::macos::{ActivationPolicy, WindowExt}; -use platform::platform::{ffi, util}; -use platform::platform::events_loop::{EventLoop, Shared}; -use platform::platform::view::{new_view, set_ime_spot}; +use platform_impl::platform::{ffi, util}; +use platform_impl::platform::events_loop::{EventLoop, Shared}; +use platform_impl::platform::view::{new_view, set_ime_spot}; use window::MonitorId as RootMonitorId; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/src/platform/mod.rs b/src/platform_impl/mod.rs similarity index 100% rename from src/platform/mod.rs rename to src/platform_impl/mod.rs diff --git a/src/platform/windows/dpi.rs b/src/platform_impl/windows/dpi.rs similarity index 100% rename from src/platform/windows/dpi.rs rename to src/platform_impl/windows/dpi.rs diff --git a/src/platform/windows/drop_handler.rs b/src/platform_impl/windows/drop_handler.rs similarity index 99% rename from src/platform/windows/drop_handler.rs rename to src/platform_impl/windows/drop_handler.rs index 43ba47d74b..0d94c12348 100644 --- a/src/platform/windows/drop_handler.rs +++ b/src/platform_impl/windows/drop_handler.rs @@ -15,7 +15,7 @@ use winapi::um::oleidl::{IDropTarget, IDropTargetVtbl}; use winapi::um::winnt::HRESULT; use winapi::um::{shellapi, unknwnbase}; -use platform::platform::WindowId; +use platform_impl::platform::WindowId; use {Event, WindowId as SuperWindowId}; diff --git a/src/platform/windows/event.rs b/src/platform_impl/windows/event.rs similarity index 100% rename from src/platform/windows/event.rs rename to src/platform_impl/windows/event.rs diff --git a/src/platform/windows/events_loop.rs b/src/platform_impl/windows/events_loop.rs similarity index 99% rename from src/platform/windows/events_loop.rs rename to src/platform_impl/windows/events_loop.rs index ee74dc35a4..f367abf7a8 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform_impl/windows/events_loop.rs @@ -52,18 +52,18 @@ use { WindowId as SuperWindowId, }; use events::{DeviceEvent, Touch, TouchPhase, StartCause}; -use platform::platform::{event, Cursor, WindowId, DEVICE_ID, wrap_device_id, util}; -use platform::platform::dpi::{ +use platform_impl::platform::{event, Cursor, WindowId, DEVICE_ID, wrap_device_id, util}; +use platform_impl::platform::dpi::{ become_dpi_aware, dpi_to_scale_factor, enable_non_client_dpi_scaling, get_hwnd_scale_factor, }; -use platform::platform::drop_handler::FileDropHandler; -use platform::platform::event::{handle_extended_keys, process_key_params, vkey_to_winit_vkey}; -use platform::platform::icon::WinIcon; -use platform::platform::raw_input::{get_raw_input_data, get_raw_mouse_button_state}; -use platform::platform::window::adjust_size; +use platform_impl::platform::drop_handler::FileDropHandler; +use platform_impl::platform::event::{handle_extended_keys, process_key_params, vkey_to_winit_vkey}; +use platform_impl::platform::icon::WinIcon; +use platform_impl::platform::raw_input::{get_raw_input_data, get_raw_mouse_button_state}; +use platform_impl::platform::window::adjust_size; /// Contains saved window info for switching between fullscreen #[derive(Clone)] diff --git a/src/platform/windows/icon.rs b/src/platform_impl/windows/icon.rs similarity index 98% rename from src/platform/windows/icon.rs rename to src/platform_impl/windows/icon.rs index 6ea1e9906d..fb265c9294 100644 --- a/src/platform/windows/icon.rs +++ b/src/platform_impl/windows/icon.rs @@ -8,7 +8,7 @@ use winapi::shared::windef::{HICON, HWND}; use winapi::um::winuser; use {Pixel, PIXEL_SIZE, Icon}; -use platform::platform::util; +use platform_impl::platform::util; impl Pixel { fn to_bgra(&mut self) { diff --git a/src/platform/windows/mod.rs b/src/platform_impl/windows/mod.rs similarity index 100% rename from src/platform/windows/mod.rs rename to src/platform_impl/windows/mod.rs diff --git a/src/platform/windows/monitor.rs b/src/platform_impl/windows/monitor.rs similarity index 97% rename from src/platform/windows/monitor.rs rename to src/platform_impl/windows/monitor.rs index b8a562ac2a..67c4aa062e 100644 --- a/src/platform/windows/monitor.rs +++ b/src/platform_impl/windows/monitor.rs @@ -8,8 +8,8 @@ use std::collections::VecDeque; use super::{EventLoop, util}; use dpi::{PhysicalPosition, PhysicalSize}; -use platform::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi}; -use platform::platform::window::Window; +use platform_impl::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi}; +use platform_impl::platform::window::Window; /// Win32 implementation of the main `MonitorId` object. #[derive(Debug, Clone)] diff --git a/src/platform/windows/raw_input.rs b/src/platform_impl/windows/raw_input.rs similarity index 99% rename from src/platform/windows/raw_input.rs rename to src/platform_impl/windows/raw_input.rs index 2f6e90594f..12664435b6 100644 --- a/src/platform/windows/raw_input.rs +++ b/src/platform_impl/windows/raw_input.rs @@ -31,7 +31,7 @@ use winapi::um::winuser::{ RID_INPUT, }; -use platform::platform::util; +use platform_impl::platform::util; use events::ElementState; #[allow(dead_code)] diff --git a/src/platform/windows/util.rs b/src/platform_impl/windows/util.rs similarity index 100% rename from src/platform/windows/util.rs rename to src/platform_impl/windows/util.rs diff --git a/src/platform/windows/window.rs b/src/platform_impl/windows/window.rs similarity index 98% rename from src/platform/windows/window.rs rename to src/platform_impl/windows/window.rs index ed66252f05..aed979a57b 100644 --- a/src/platform/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -28,15 +28,15 @@ use { PhysicalSize, WindowAttributes, }; -use platform::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, WindowId}; -use platform::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi}; -use platform::platform::events_loop::{self, EventLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}; -use platform::platform::events_loop::WindowState; -use platform::platform::icon::{self, IconType, WinIcon}; -use platform::platform::monitor; -use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input; -use platform::platform::drop_handler::FileDropHandler; -use platform::platform::util; +use platform_impl::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, WindowId}; +use platform_impl::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi}; +use platform_impl::platform::events_loop::{self, EventLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}; +use platform_impl::platform::events_loop::WindowState; +use platform_impl::platform::icon::{self, IconType, WinIcon}; +use platform_impl::platform::monitor; +use platform_impl::platform::raw_input::register_all_mice_and_keyboards_for_raw_input; +use platform_impl::platform::drop_handler::FileDropHandler; +use platform_impl::platform::util; const WS_RESIZABLE: DWORD = winuser::WS_SIZEBOX | winuser::WS_MAXIMIZEBOX; diff --git a/src/window.rs b/src/window.rs index 0abba65f14..d80807e802 100644 --- a/src/window.rs +++ b/src/window.rs @@ -9,7 +9,7 @@ use { MouseCursor, PhysicalPosition, PhysicalSize, - platform, + platform_impl, Window, WindowBuilder, WindowId, @@ -154,7 +154,7 @@ impl WindowBuilder { })); // building - platform::Window::new( + platform_impl::Window::new( &events_loop.events_loop, self.window, self.platform_specific, @@ -449,7 +449,7 @@ impl Window { // This may change in the future. #[derive(Debug)] pub struct AvailableMonitorsIter { - pub(crate) data: VecDequeIter, + pub(crate) data: VecDequeIter, } impl Iterator for AvailableMonitorsIter { @@ -469,7 +469,7 @@ impl Iterator for AvailableMonitorsIter { /// Identifier for a monitor. #[derive(Debug, Clone)] pub struct MonitorId { - pub(crate) inner: platform::MonitorId + pub(crate) inner: platform_impl::MonitorId } impl MonitorId { From dad24d086aaaff60e557efc4f41d1ae7e3c71738 Mon Sep 17 00:00:00 2001 From: Osspial Date: Wed, 22 Aug 2018 18:03:41 -0400 Subject: [PATCH 12/40] Rename os to platform, add Ext trait postfixes --- src/lib.rs | 2 +- src/{os => platform}/android.rs | 12 ++++++------ src/{os => platform}/ios.rs | 12 ++++++------ src/{os => platform}/macos.rs | 12 ++++++------ src/{os => platform}/mod.rs | 0 src/{os => platform}/unix.rs | 16 ++++++++-------- src/{os => platform}/windows.rs | 20 ++++++++++---------- 7 files changed, 37 insertions(+), 37 deletions(-) rename src/{os => platform}/android.rs (78%) rename src/{os => platform}/ios.rs (89%) rename src/{os => platform}/macos.rs (96%) rename src/{os => platform}/mod.rs (100%) rename src/{os => platform}/unix.rs (97%) rename src/{os => platform}/windows.rs (89%) diff --git a/src/lib.rs b/src/lib.rs index c5378a3ec1..a06315cf30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ mod icon; mod platform_impl; mod window; -pub mod os; +pub mod platform; /// Represents a window. /// diff --git a/src/os/android.rs b/src/platform/android.rs similarity index 78% rename from src/os/android.rs rename to src/platform/android.rs index 2efe95c1d3..67ce262688 100644 --- a/src/os/android.rs +++ b/src/platform/android.rs @@ -6,23 +6,23 @@ use Window; use WindowBuilder; /// Additional methods on `EventLoop` that are specific to Android. -pub trait EventLoopExt { +pub trait EventLoopExtAndroid { /// Makes it possible for glutin to register a callback when a suspend event happens on Android fn set_suspend_callback(&self, cb: Option ()>>); } -impl EventLoopExt for EventLoop { +impl EventLoopExtAndroid for EventLoop { fn set_suspend_callback(&self, cb: Option ()>>) { self.events_loop.set_suspend_callback(cb); } } /// Additional methods on `Window` that are specific to Android. -pub trait WindowExt { +pub trait WindowExtAndroid { fn get_native_window(&self) -> *const c_void; } -impl WindowExt for Window { +impl WindowExtAndroid for Window { #[inline] fn get_native_window(&self) -> *const c_void { self.window.get_native_window() @@ -30,9 +30,9 @@ impl WindowExt for Window { } /// Additional methods on `WindowBuilder` that are specific to Android. -pub trait WindowBuilderExt { +pub trait WindowBuilderExtAndroid { } -impl WindowBuilderExt for WindowBuilder { +impl WindowBuilderExtAndroid for WindowBuilder { } diff --git a/src/os/ios.rs b/src/platform/ios.rs similarity index 89% rename from src/os/ios.rs rename to src/platform/ios.rs index 62c2c2470f..3e7a3e2a7b 100644 --- a/src/os/ios.rs +++ b/src/platform/ios.rs @@ -5,7 +5,7 @@ use std::os::raw::c_void; use {MonitorId, Window, WindowBuilder}; /// Additional methods on `Window` that are specific to iOS. -pub trait WindowExt { +pub trait WindowExtIOS { /// Returns a pointer to the `UIWindow` that is used by this window. /// /// The pointer will become invalid when the `Window` is destroyed. @@ -17,7 +17,7 @@ pub trait WindowExt { fn get_uiview(&self) -> *mut c_void; } -impl WindowExt for Window { +impl WindowExtIOS for Window { #[inline] fn get_uiwindow(&self) -> *mut c_void { self.window.get_uiwindow() as _ @@ -30,14 +30,14 @@ impl WindowExt for Window { } /// Additional methods on `WindowBuilder` that are specific to iOS. -pub trait WindowBuilderExt { +pub trait WindowBuilderExtIOS { /// Sets the root view class used by the `Window`, otherwise a barebones `UIView` is provided. /// /// The class will be initialized by calling `[root_view initWithFrame:CGRect]` fn with_root_view_class(self, root_view_class: *const c_void) -> WindowBuilder; } -impl WindowBuilderExt for WindowBuilder { +impl WindowBuilderExtIOS for WindowBuilder { #[inline] fn with_root_view_class(mut self, root_view_class: *const c_void) -> WindowBuilder { self.platform_specific.root_view_class = unsafe { &*(root_view_class as *const _) }; @@ -46,12 +46,12 @@ impl WindowBuilderExt for WindowBuilder { } /// Additional methods on `MonitorId` that are specific to iOS. -pub trait MonitorIdExt { +pub trait MonitorIdExtIOS { /// Returns a pointer to the `UIScreen` that is used by this monitor. fn get_uiscreen(&self) -> *mut c_void; } -impl MonitorIdExt for MonitorId { +impl MonitorIdExtIOS for MonitorId { #[inline] fn get_uiscreen(&self) -> *mut c_void { self.inner.get_uiscreen() as _ diff --git a/src/os/macos.rs b/src/platform/macos.rs similarity index 96% rename from src/os/macos.rs rename to src/platform/macos.rs index 7118eeb946..24bdc426bd 100644 --- a/src/os/macos.rs +++ b/src/platform/macos.rs @@ -4,7 +4,7 @@ use std::os::raw::c_void; use {LogicalSize, MonitorId, Window, WindowBuilder}; /// Additional methods on `Window` that are specific to MacOS. -pub trait WindowExt { +pub trait WindowExtMacOS { /// Returns a pointer to the cocoa `NSWindow` that is used by this window. /// /// The pointer will become invalid when the `Window` is destroyed. @@ -24,7 +24,7 @@ pub trait WindowExt { fn request_user_attention(&self, is_critical: bool); } -impl WindowExt for Window { +impl WindowExtMacOS for Window { #[inline] fn get_nswindow(&self) -> *mut c_void { self.window.get_nswindow() @@ -68,7 +68,7 @@ impl Default for ActivationPolicy { /// - `with_titlebar_hidden` /// - `with_titlebar_buttons_hidden` /// - `with_fullsize_content_view` -pub trait WindowBuilderExt { +pub trait WindowBuilderExtMacOS { /// Sets the activation policy for the window being built. fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder; /// Enables click-and-drag behavior for the entire window, not just the titlebar. @@ -87,7 +87,7 @@ pub trait WindowBuilderExt { fn with_resize_increments(self, increments: LogicalSize) -> WindowBuilder; } -impl WindowBuilderExt for WindowBuilder { +impl WindowBuilderExtMacOS for WindowBuilder { #[inline] fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder { self.platform_specific.activation_policy = activation_policy; @@ -138,14 +138,14 @@ impl WindowBuilderExt for WindowBuilder { } /// Additional methods on `MonitorId` that are specific to MacOS. -pub trait MonitorIdExt { +pub trait MonitorIdExtMacOS { /// Returns the identifier of the monitor for Cocoa. fn native_id(&self) -> u32; /// Returns a pointer to the NSScreen representing this monitor. fn get_nsscreen(&self) -> Option<*mut c_void>; } -impl MonitorIdExt for MonitorId { +impl MonitorIdExtMacOS for MonitorId { #[inline] fn native_id(&self) -> u32 { self.inner.get_native_identifier() diff --git a/src/os/mod.rs b/src/platform/mod.rs similarity index 100% rename from src/os/mod.rs rename to src/platform/mod.rs diff --git a/src/os/unix.rs b/src/platform/unix.rs similarity index 97% rename from src/os/unix.rs rename to src/platform/unix.rs index 7b2640030a..7a0929d8e6 100644 --- a/src/os/unix.rs +++ b/src/platform/unix.rs @@ -26,7 +26,7 @@ pub use platform_impl::XNotSupported; pub use platform_impl::x11::util::WindowType as XWindowType; /// Additional methods on `EventLoop` that are specific to Linux. -pub trait EventLoopExt { +pub trait EventLoopExtUnix { /// Builds a new `EventLoop` that is forced to use X11. fn new_x11() -> Result where Self: Sized; @@ -45,7 +45,7 @@ pub trait EventLoopExt { fn get_xlib_xconnection(&self) -> Option>; } -impl EventLoopExt for EventLoop { +impl EventLoopExtUnix for EventLoop { #[inline] fn new_x11() -> Result { LinuxEventLoop::new_x11().map(|ev| @@ -85,7 +85,7 @@ impl EventLoopExt for EventLoop { } /// Additional methods on `Window` that are specific to Unix. -pub trait WindowExt { +pub trait WindowExtUnix { /// Returns the ID of the `Window` xlib object that is used by this window. /// /// Returns `None` if the window doesn't use xlib (if it uses wayland for example). @@ -137,7 +137,7 @@ pub trait WindowExt { fn is_ready(&self) -> bool; } -impl WindowExt for Window { +impl WindowExtUnix for Window { #[inline] fn get_xlib_window(&self) -> Option { match self.window { @@ -209,7 +209,7 @@ impl WindowExt for Window { } /// Additional methods on `WindowBuilder` that are specific to Unix. -pub trait WindowBuilderExt { +pub trait WindowBuilderExtUnix { fn with_x11_visual(self, visual_infos: *const T) -> WindowBuilder; fn with_x11_screen(self, screen_id: i32) -> WindowBuilder; @@ -227,7 +227,7 @@ pub trait WindowBuilderExt { fn with_base_size(self, base_size: LogicalSize) -> WindowBuilder; } -impl WindowBuilderExt for WindowBuilder { +impl WindowBuilderExtUnix for WindowBuilder { #[inline] fn with_x11_visual(mut self, visual_infos: *const T) -> WindowBuilder { self.platform_specific.visual_infos = Some( @@ -280,12 +280,12 @@ impl WindowBuilderExt for WindowBuilder { } /// Additional methods on `MonitorId` that are specific to Linux. -pub trait MonitorIdExt { +pub trait MonitorIdExtUnix { /// Returns the inner identifier of the monitor. fn native_id(&self) -> u32; } -impl MonitorIdExt for MonitorId { +impl MonitorIdExtUnix for MonitorId { #[inline] fn native_id(&self) -> u32 { self.inner.get_native_identifier() diff --git a/src/os/windows.rs b/src/platform/windows.rs similarity index 89% rename from src/os/windows.rs rename to src/platform/windows.rs index 96a178041c..b792d9aa85 100644 --- a/src/os/windows.rs +++ b/src/platform/windows.rs @@ -9,13 +9,13 @@ use {DeviceId, EventLoop, Icon, MonitorId, Window, WindowBuilder}; use platform_impl::EventLoop as WindowsEventLoop; /// Additional methods on `EventLoop` that are specific to Windows. -pub trait EventLoopExt { +pub trait EventLoopExtWindows { /// By default, winit on Windows will attempt to enable process-wide DPI awareness. If that's /// undesirable, you can create an `EventLoop` using this function instead. fn new_dpi_unaware() -> Self where Self: Sized; } -impl EventLoopExt for EventLoop { +impl EventLoopExtWindows for EventLoop { #[inline] fn new_dpi_unaware() -> Self { EventLoop { @@ -26,7 +26,7 @@ impl EventLoopExt for EventLoop { } /// Additional methods on `Window` that are specific to Windows. -pub trait WindowExt { +pub trait WindowExtWindows { /// Returns the native handle that is used by this window. /// /// The pointer will become invalid when the native window was destroyed. @@ -36,7 +36,7 @@ pub trait WindowExt { fn set_taskbar_icon(&self, taskbar_icon: Option); } -impl WindowExt for Window { +impl WindowExtWindows for Window { #[inline] fn get_hwnd(&self) -> *mut libc::c_void { self.window.hwnd() as *mut _ @@ -49,7 +49,7 @@ impl WindowExt for Window { } /// Additional methods on `WindowBuilder` that are specific to Windows. -pub trait WindowBuilderExt { +pub trait WindowBuilderExtWindows { /// Sets a parent to the window to be created. fn with_parent_window(self, parent: HWND) -> WindowBuilder; @@ -60,7 +60,7 @@ pub trait WindowBuilderExt { fn with_no_redirection_bitmap(self, flag: bool) -> WindowBuilder; } -impl WindowBuilderExt for WindowBuilder { +impl WindowBuilderExtWindows for WindowBuilder { #[inline] fn with_parent_window(mut self, parent: HWND) -> WindowBuilder { self.platform_specific.parent = Some(parent); @@ -81,7 +81,7 @@ impl WindowBuilderExt for WindowBuilder { } /// Additional methods on `MonitorId` that are specific to Windows. -pub trait MonitorIdExt { +pub trait MonitorIdExtWindows { /// Returns the name of the monitor adapter specific to the Win32 API. fn native_id(&self) -> String; @@ -89,7 +89,7 @@ pub trait MonitorIdExt { fn hmonitor(&self) -> *mut c_void; } -impl MonitorIdExt for MonitorId { +impl MonitorIdExtWindows for MonitorId { #[inline] fn native_id(&self) -> String { self.inner.get_native_identifier() @@ -102,14 +102,14 @@ impl MonitorIdExt for MonitorId { } /// Additional methods on `DeviceId` that are specific to Windows. -pub trait DeviceIdExt { +pub trait DeviceIdExtWindows { /// Returns an identifier that persistently refers to this specific device. /// /// Will return `None` if the device is no longer available. fn get_persistent_identifier(&self) -> Option; } -impl DeviceIdExt for DeviceId { +impl DeviceIdExtWindows for DeviceId { #[inline] fn get_persistent_identifier(&self) -> Option { self.0.get_persistent_identifier() From f20fac99f6ac57c51603a92d792fd4f665feb7f6 Mon Sep 17 00:00:00 2001 From: Osspial Date: Wed, 22 Aug 2018 22:07:39 -0400 Subject: [PATCH 13/40] Add platform::desktop module with EventLoopExt::run_return --- examples/run_return.rs | 41 +++++++++++++ src/platform/desktop.rs | 28 +++++++++ src/platform/mod.rs | 2 + src/platform_impl/windows/events_loop.rs | 77 +++++++++++++----------- 4 files changed, 114 insertions(+), 34 deletions(-) create mode 100644 examples/run_return.rs create mode 100644 src/platform/desktop.rs diff --git a/examples/run_return.rs b/examples/run_return.rs new file mode 100644 index 0000000000..d93b9aa81c --- /dev/null +++ b/examples/run_return.rs @@ -0,0 +1,41 @@ +extern crate winit; +use winit::platform::desktop::EventLoopExtDesktop; + +fn main() { + let mut events_loop = winit::EventLoop::new(); + + let window = winit::WindowBuilder::new() + .with_title("A fantastic window!") + .build(&events_loop) + .unwrap(); + + println!("Close the window to continue."); + events_loop.run_return(|event, _, control_flow| { + match event { + winit::Event::WindowEvent { + event: winit::WindowEvent::CloseRequested, + .. + } => *control_flow = winit::ControlFlow::Exit, + _ => *control_flow = winit::ControlFlow::Wait, + } + }); + drop(window); + + let _window_2 = winit::WindowBuilder::new() + .with_title("A second, fantasticer window!") + .build(&events_loop) + .unwrap(); + + println!("Wa ha ha! You thought that closing the window would finish this?!"); + events_loop.run_return(|event, _, control_flow| { + match event { + winit::Event::WindowEvent { + event: winit::WindowEvent::CloseRequested, + .. + } => *control_flow = winit::ControlFlow::Exit, + _ => *control_flow = winit::ControlFlow::Wait, + } + }); + + println!("Okay we're done now for real."); +} diff --git a/src/platform/desktop.rs b/src/platform/desktop.rs new file mode 100644 index 0000000000..5ab9be6668 --- /dev/null +++ b/src/platform/desktop.rs @@ -0,0 +1,28 @@ +#![cfg(any( + target_os = "windows", + target_os = "macos", + target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd" +))] + +use {EventLoop, Event, ControlFlow}; + +/// Additional methods on `EventLoop` that are specific to desktop platforms. +pub trait EventLoopExtDesktop { + type UserEvent; + /// Initializes the `winit` event loop. + /// + /// Unlikes `run`, this function *does* return control flow to the caller when `control_flow` + /// is set to `ControlFlow::Exit`. + fn run_return(&mut self, event_handler: F) + where F: FnMut(Event, &EventLoop, &mut ControlFlow); +} + +impl EventLoopExtDesktop for EventLoop { + type UserEvent = T; + + fn run_return(&mut self, event_handler: F) + where F: FnMut(Event, &EventLoop, &mut ControlFlow) + { + self.events_loop.run_return(event_handler) + } +} diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 2496769563..27ce048d99 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -15,3 +15,5 @@ pub mod ios; pub mod macos; pub mod unix; pub mod windows; + +pub mod desktop; diff --git a/src/platform_impl/windows/events_loop.rs b/src/platform_impl/windows/events_loop.rs index f367abf7a8..dba70c0591 100644 --- a/src/platform_impl/windows/events_loop.rs +++ b/src/platform_impl/windows/events_loop.rs @@ -182,35 +182,44 @@ impl EventLoop { } } - pub fn run(self, mut event_handler: F) -> ! + pub fn run(mut self, event_handler: F) -> ! where F: 'static + FnMut(Event, &::EventLoop, &mut ControlFlow) { - unsafe { - winuser::IsGUIThread(1); + self.run_return(event_handler); + ::std::process::exit(0); + } - let mut runner = EventLoopRunner { - event_loop: ::EventLoop { - events_loop: self, - _marker: ::std::marker::PhantomData - }, - control_flow: ControlFlow::default(), - runner_state: RunnerState::New, - modal_loop_data: None, - event_handler: &mut event_handler - }; - { - let runner_shared = runner.event_loop.events_loop.runner_shared.clone(); - let mut runner_shared = runner_shared.borrow_mut(); - let mut event_buffer = vec![]; - if let ELRSharedOption::Buffer(ref mut buffer) = *runner_shared { - mem::swap(buffer, &mut event_buffer); - } - for event in event_buffer.drain(..) { - runner.process_event(event); - } - *runner_shared = ELRSharedOption::Runner(&mut runner); + pub fn run_return(&mut self, mut event_handler: F) + where F: FnMut(Event, &::EventLoop, &mut ControlFlow) + { + unsafe{ winuser::IsGUIThread(1); } + let mut runner = EventLoopRunner { + event_loop: self, + control_flow: ControlFlow::default(), + runner_state: RunnerState::New, + modal_loop_data: None, + event_handler: unsafe { + // Transmute used to erase lifetimes. + mem::transmute::< + &mut FnMut(Event, &::EventLoop, &mut ControlFlow), + *mut FnMut(Event, &::EventLoop, &mut ControlFlow) + >(&mut event_handler) } + }; + { + let runner_shared = self.runner_shared.clone(); + let mut runner_shared = runner_shared.borrow_mut(); + let mut event_buffer = vec![]; + if let ELRSharedOption::Buffer(ref mut buffer) = *runner_shared { + mem::swap(buffer, &mut event_buffer); + } + for event in event_buffer.drain(..) { + unsafe{ runner.process_event(event); } + } + *runner_shared = ELRSharedOption::Runner(&mut runner); + } + unsafe { let timer_handle = winuser::SetTimer(ptr::null_mut(), 0, 0x7FFFFFFF, None); let mut msg = mem::uninitialized(); @@ -253,13 +262,10 @@ impl EventLoop { ControlFlow::Poll => () } } - - runner.call_event_handler(Event::LoopDestroyed); - *runner.event_loop.events_loop.runner_shared.borrow_mut() = ELRSharedOption::Buffer(vec![]); } - drop(event_handler); - ::std::process::exit(0); + unsafe{ runner.call_event_handler(Event::LoopDestroyed) } + *self.runner_shared.borrow_mut() = ELRSharedOption::Buffer(vec![]); } pub fn create_proxy(&self) -> EventLoopProxy { @@ -284,7 +290,7 @@ pub(crate) enum ELRSharedOption { Buffer(Vec>) } pub(crate) struct EventLoopRunner { - event_loop: ::EventLoop, + event_loop: *const EventLoop, control_flow: ControlFlow, runner_state: RunnerState, modal_loop_data: Option, @@ -457,15 +463,18 @@ impl EventLoopRunner { unsafe fn call_event_handler(&mut self, event: Event) { if self.event_handler != mem::zeroed() { match event { - Event::NewEvents(_) => self.event_loop.events_loop.trigger_newevents_on_redraw.store(true, Ordering::Relaxed), - Event::EventsCleared => self.event_loop.events_loop.trigger_newevents_on_redraw.store(false, Ordering::Relaxed), + Event::NewEvents(_) => (*self.event_loop).trigger_newevents_on_redraw.store(true, Ordering::Relaxed), + Event::EventsCleared => (*self.event_loop).trigger_newevents_on_redraw.store(false, Ordering::Relaxed), _ => () } + assert_eq!(mem::size_of::<::EventLoop>(), mem::size_of::>()); + let event_loop_ref = &*(self.event_loop as *const ::EventLoop); + if self.control_flow != ControlFlow::Exit { - (*self.event_handler)(event, &self.event_loop, &mut self.control_flow); + (*self.event_handler)(event, event_loop_ref, &mut self.control_flow); } else { - (*self.event_handler)(event, &self.event_loop, &mut ControlFlow::Exit); + (*self.event_handler)(event, event_loop_ref, &mut ControlFlow::Exit); } } else { panic!("Tried to call event handler with null handler"); From 4377680a44ea86dad52954f90bc7d8ad7ed0b4bf Mon Sep 17 00:00:00 2001 From: Osspial Date: Wed, 22 Aug 2018 23:01:36 -0400 Subject: [PATCH 14/40] Re-organize into module structure --- examples/cursor.rs | 6 +- examples/cursor_grab.rs | 25 +- examples/fullscreen.rs | 18 +- examples/handling_close.rs | 25 +- examples/min_max_size.rs | 13 +- examples/monitor_list.rs | 6 +- examples/multiwindow.rs | 19 +- examples/proxy.rs | 10 +- examples/request_redraw.rs | 13 +- examples/resizable.rs | 21 +- examples/run_return.rs | 26 +- examples/timer.rs | 8 +- examples/transparent.rs | 13 +- examples/window.rs | 15 +- examples/window_icon.rs | 19 +- src/{events.rs => event.rs} | 12 +- src/event_loop.rs | 151 ++++++++ src/lib.rs | 412 +--------------------- src/monitor.rs | 68 ++++ src/platform/desktop.rs | 3 +- src/platform/windows.rs | 5 +- src/platform_impl/windows/drop_handler.rs | 9 +- src/platform_impl/windows/event.rs | 5 +- src/platform_impl/windows/events_loop.rs | 179 +++++----- src/platform_impl/windows/icon.rs | 2 +- src/platform_impl/windows/mod.rs | 11 +- src/platform_impl/windows/raw_input.rs | 2 +- src/platform_impl/windows/window.rs | 13 +- src/window.rs | 302 ++++++++++++---- tests/send_objects.rs | 10 +- tests/sync_object.rs | 2 +- 31 files changed, 731 insertions(+), 692 deletions(-) rename src/{events.rs => event.rs} (96%) create mode 100644 src/event_loop.rs create mode 100644 src/monitor.rs diff --git a/examples/cursor.rs b/examples/cursor.rs index 81a1a1cd33..31d28aef7f 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -1,11 +1,13 @@ extern crate winit; -use winit::{Event, EventLoop, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow}; +use winit::window::{WindowBuilder, MouseCursor}; +use winit::event::{Event, WindowEvent, ElementState, KeyboardInput}; +use winit::event_loop::{EventLoop, ControlFlow}; fn main() { let events_loop = EventLoop::new(); - let window = winit::WindowBuilder::new().build(&events_loop).unwrap(); + let window = WindowBuilder::new().build(&events_loop).unwrap(); window.set_title("A fantastic window!"); let mut cursor_idx = 0; diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index 392a68d2e0..101cf33fba 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -1,31 +1,34 @@ extern crate winit; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent, ElementState, KeyboardInput}; +use winit::event_loop::{EventLoop, ControlFlow}; + fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); - let window = winit::WindowBuilder::new() + let window = WindowBuilder::new() .with_title("Super Cursor Grab'n'Hide Simulator 9000") .build(&events_loop) .unwrap(); events_loop.run(move |event, _, control_flow| { - *control_flow = winit::ControlFlow::Wait; - if let winit::Event::WindowEvent { event, .. } = event { - use winit::WindowEvent::*; + *control_flow = ControlFlow::Wait; + if let Event::WindowEvent { event, .. } = event { match event { - CloseRequested => *control_flow = winit::ControlFlow::Exit, - KeyboardInput { - input: winit::KeyboardInput { - state: winit::ElementState::Released, + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::KeyboardInput { + input: KeyboardInput { + state: ElementState::Released, virtual_keycode: Some(key), modifiers, .. }, .. } => { - use winit::VirtualKeyCode::*; + use winit::event::VirtualKeyCode::*; match key { - Escape => *control_flow = winit::ControlFlow::Exit, + Escape => *control_flow = ControlFlow::Exit, G => window.grab_cursor(!modifiers.shift).unwrap(), H => window.hide_cursor(!modifiers.shift), _ => (), diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index 95afca0673..eda82b72a5 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -1,10 +1,12 @@ extern crate winit; use std::io::{self, Write}; -use winit::{ControlFlow, Event, WindowEvent}; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInput}; +use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); // enumerating monitors let monitor = { @@ -25,7 +27,7 @@ fn main() { monitor }; - let window = winit::WindowBuilder::new() + let window = WindowBuilder::new() .with_title("Hello world!") .with_fullscreen(Some(monitor)) .build(&events_loop) @@ -44,15 +46,15 @@ fn main() { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::KeyboardInput { input: - winit::KeyboardInput { + KeyboardInput { virtual_keycode: Some(virtual_code), state, .. }, .. } => match (virtual_code, state) { - (winit::VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit, - (winit::VirtualKeyCode::F, winit::ElementState::Pressed) => { + (VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit, + (VirtualKeyCode::F, ElementState::Pressed) => { is_fullscreen = !is_fullscreen; if !is_fullscreen { window.set_fullscreen(None); @@ -60,11 +62,11 @@ fn main() { window.set_fullscreen(Some(window.get_current_monitor())); } } - (winit::VirtualKeyCode::M, winit::ElementState::Pressed) => { + (VirtualKeyCode::M, ElementState::Pressed) => { is_maximized = !is_maximized; window.set_maximized(is_maximized); } - (winit::VirtualKeyCode::D, winit::ElementState::Pressed) => { + (VirtualKeyCode::D, ElementState::Pressed) => { decorations = !decorations; window.set_decorations(decorations); } diff --git a/examples/handling_close.rs b/examples/handling_close.rs index b0189c3b71..8702270bcd 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -1,9 +1,13 @@ extern crate winit; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent, KeyboardInput}; +use winit::event_loop::{EventLoop, ControlFlow}; + fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); - let _window = winit::WindowBuilder::new() + let _window = WindowBuilder::new() .with_title("Your faithful window") .build(&events_loop) .unwrap(); @@ -11,13 +15,12 @@ fn main() { let mut close_requested = false; events_loop.run(move |event, _, control_flow| { - use winit::WindowEvent::*; - use winit::ElementState::Released; - use winit::VirtualKeyCode::{N, Y}; + use winit::event::ElementState::Released; + use winit::event::VirtualKeyCode::{N, Y}; match event { - winit::Event::WindowEvent { event, .. } => match event { - CloseRequested => { + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => { // `CloseRequested` is sent when the close button on the window is pressed (or // through whatever other mechanisms the window manager provides for closing a // window). If you don't handle this event, the close button won't actually do @@ -34,9 +37,9 @@ fn main() { // closing the window. How to close the window is detailed in the handler for // the Y key. } - KeyboardInput { + WindowEvent::KeyboardInput { input: - winit::KeyboardInput { + KeyboardInput { virtual_keycode: Some(virtual_code), state: Released, .. @@ -53,7 +56,7 @@ fn main() { // event loop (i.e. if it's a multi-window application), you need to // drop the window. That closes it, and results in `Destroyed` being // sent. - *control_flow = winit::ControlFlow::Exit; + *control_flow = ControlFlow::Exit; } } N => { @@ -69,6 +72,6 @@ fn main() { _ => (), } - *control_flow = winit::ControlFlow::Wait; + *control_flow = ControlFlow::Wait; }); } diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index 88d4823d89..4a8a4e25da 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -1,11 +1,14 @@ extern crate winit; use winit::dpi::LogicalSize; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); - let window = winit::WindowBuilder::new() + let window = WindowBuilder::new() .build(&events_loop) .unwrap(); @@ -16,9 +19,9 @@ fn main() { println!("{:?}", event); match event { - winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => - *control_flow = winit::ControlFlow::Exit, - _ => *control_flow = winit::ControlFlow::Wait, + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => + *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, } }); } diff --git a/examples/monitor_list.rs b/examples/monitor_list.rs index 635f2fb808..335aa02281 100644 --- a/examples/monitor_list.rs +++ b/examples/monitor_list.rs @@ -1,7 +1,9 @@ extern crate winit; +use winit::event_loop::EventLoop; +use winit::window::WindowBuilder; fn main() { - let event_loop = winit::EventLoop::new(); - let window = winit::WindowBuilder::new().build(&event_loop).unwrap(); + let event_loop = EventLoop::new(); + let window = WindowBuilder::new().build(&event_loop).unwrap(); println!("{:#?}\nPrimary: {:#?}", window.get_available_monitors(), window.get_primary_monitor()); } diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index c4278828df..b5774b5066 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -1,33 +1,36 @@ extern crate winit; use std::collections::HashMap; +use winit::window::Window; +use winit::event::{Event, WindowEvent, ElementState, KeyboardInput}; +use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); let mut windows = HashMap::new(); for _ in 0..3 { - let window = winit::Window::new(&events_loop).unwrap(); + let window = Window::new(&events_loop).unwrap(); windows.insert(window.id(), window); } events_loop.run(move |event, events_loop, control_flow| { - *control_flow = winit::ControlFlow::Wait; + *control_flow = ControlFlow::Wait; match event { - winit::Event::WindowEvent { event, window_id } => { + Event::WindowEvent { event, window_id } => { match event { - winit::WindowEvent::CloseRequested => { + WindowEvent::CloseRequested => { println!("Window {:?} has received the signal to close", window_id); // This drops the window, causing it to close. windows.remove(&window_id); if windows.is_empty() { - *control_flow = winit::ControlFlow::Exit; + *control_flow = ControlFlow::Exit; } }, - winit::WindowEvent::KeyboardInput{..} => { - let window = winit::Window::new(&events_loop).unwrap(); + WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. } => { + let window = Window::new(&events_loop).unwrap(); windows.insert(window.id(), window); }, _ => () diff --git a/examples/proxy.rs b/examples/proxy.rs index fe648ed66b..f1106fb891 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -1,5 +1,7 @@ extern crate winit; -use winit::{EventLoop, WindowBuilder}; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{EventLoop, ControlFlow}; fn main() { let events_loop: EventLoop = EventLoop::new_user_event(); @@ -24,9 +26,9 @@ fn main() { events_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { - winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => - *control_flow = winit::ControlFlow::Exit, - _ => *control_flow = winit::ControlFlow::Wait, + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => + *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, } }); } diff --git a/examples/request_redraw.rs b/examples/request_redraw.rs index a870fb8df0..2943953b39 100644 --- a/examples/request_redraw.rs +++ b/examples/request_redraw.rs @@ -1,11 +1,14 @@ extern crate winit; -use winit::{Event, WindowEvent}; use std::time::{Instant, Duration}; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{EventLoop, ControlFlow}; + fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); - let window = winit::WindowBuilder::new() + let window = WindowBuilder::new() .with_title("A fantastic window!") .build(&events_loop) .unwrap(); @@ -17,10 +20,10 @@ fn main() { Event::WindowEvent { event: WindowEvent::CloseRequested, .. - } => *control_flow = winit::ControlFlow::Exit, + } => *control_flow = ControlFlow::Exit, Event::EventsCleared => { window.request_redraw(); - *control_flow = winit::ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0)) + *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::new(1, 0)) }, _ => () } diff --git a/examples/resizable.rs b/examples/resizable.rs index fd75860d8d..b9df0a5f02 100644 --- a/examples/resizable.rs +++ b/examples/resizable.rs @@ -1,11 +1,14 @@ extern crate winit; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInput}; +use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); let mut resizable = false; - let window = winit::WindowBuilder::new() + let window = WindowBuilder::new() .with_title("Hit space to toggle resizability.") .with_dimensions((400, 200).into()) .with_resizable(resizable) @@ -13,15 +16,15 @@ fn main() { .unwrap(); events_loop.run(move |event, _, control_flow| { - *control_flow = winit::ControlFlow::Wait; + *control_flow = ControlFlow::Wait; match event { - winit::Event::WindowEvent { event, .. } => match event { - winit::WindowEvent::CloseRequested => *control_flow = winit::ControlFlow::Exit, - winit::WindowEvent::KeyboardInput { + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::KeyboardInput { input: - winit::KeyboardInput { - virtual_keycode: Some(winit::VirtualKeyCode::Space), - state: winit::ElementState::Released, + KeyboardInput { + virtual_keycode: Some(VirtualKeyCode::Space), + state: ElementState::Released, .. }, .. diff --git a/examples/run_return.rs b/examples/run_return.rs index d93b9aa81c..d38dcf5c4f 100644 --- a/examples/run_return.rs +++ b/examples/run_return.rs @@ -1,10 +1,14 @@ extern crate winit; + +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{EventLoop, ControlFlow}; use winit::platform::desktop::EventLoopExtDesktop; fn main() { - let mut events_loop = winit::EventLoop::new(); + let mut events_loop = EventLoop::new(); - let window = winit::WindowBuilder::new() + let window = WindowBuilder::new() .with_title("A fantastic window!") .build(&events_loop) .unwrap(); @@ -12,16 +16,16 @@ fn main() { println!("Close the window to continue."); events_loop.run_return(|event, _, control_flow| { match event { - winit::Event::WindowEvent { - event: winit::WindowEvent::CloseRequested, + Event::WindowEvent { + event: WindowEvent::CloseRequested, .. - } => *control_flow = winit::ControlFlow::Exit, - _ => *control_flow = winit::ControlFlow::Wait, + } => *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, } }); drop(window); - let _window_2 = winit::WindowBuilder::new() + let _window_2 = WindowBuilder::new() .with_title("A second, fantasticer window!") .build(&events_loop) .unwrap(); @@ -29,11 +33,11 @@ fn main() { println!("Wa ha ha! You thought that closing the window would finish this?!"); events_loop.run_return(|event, _, control_flow| { match event { - winit::Event::WindowEvent { - event: winit::WindowEvent::CloseRequested, + Event::WindowEvent { + event: WindowEvent::CloseRequested, .. - } => *control_flow = winit::ControlFlow::Exit, - _ => *control_flow = winit::ControlFlow::Wait, + } => *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, } }); diff --git a/examples/timer.rs b/examples/timer.rs index 3df30c919b..fb28a73b80 100644 --- a/examples/timer.rs +++ b/examples/timer.rs @@ -1,11 +1,13 @@ extern crate winit; use std::time::{Duration, Instant}; -use winit::{Event, WindowEvent, StartCause, ControlFlow}; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent, StartCause}; +use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); - let _window = winit::WindowBuilder::new() + let _window = WindowBuilder::new() .with_title("A fantastic window!") .build(&events_loop) .unwrap(); diff --git a/examples/transparent.rs b/examples/transparent.rs index 321b907163..593f2865da 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -1,9 +1,12 @@ extern crate winit; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); - let window = winit::WindowBuilder::new().with_decorations(false) + let window = WindowBuilder::new().with_decorations(false) .with_transparency(true) .build(&events_loop).unwrap(); @@ -13,9 +16,9 @@ fn main() { println!("{:?}", event); match event { - winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => - *control_flow = winit::ControlFlow::Exit, - _ => *control_flow = winit::ControlFlow::Wait, + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => + *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, } }); } diff --git a/examples/window.rs b/examples/window.rs index 5c6f753e8a..ef7c790c63 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -1,9 +1,12 @@ extern crate winit; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); - let _window = winit::WindowBuilder::new() + let _window = WindowBuilder::new() .with_title("A fantastic window!") .build(&events_loop) .unwrap(); @@ -12,11 +15,11 @@ fn main() { println!("{:?}", event); match event { - winit::Event::WindowEvent { - event: winit::WindowEvent::CloseRequested, + Event::WindowEvent { + event: WindowEvent::CloseRequested, .. - } => *control_flow = winit::ControlFlow::Exit, - _ => *control_flow = winit::ControlFlow::Wait, + } => *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, } }); } diff --git a/examples/window_icon.rs b/examples/window_icon.rs index 691ec09ad8..9db3e0f050 100644 --- a/examples/window_icon.rs +++ b/examples/window_icon.rs @@ -8,7 +8,14 @@ extern crate image; #[cfg(feature = "icon_loading")] fn main() { +<<<<<<< HEAD use winit::Icon; +======= + use winit::window::{WindowBuilder, Icon}; + use winit::event::Event; + use winit::event_loop::{EventLoop, ControlFlow}; + +>>>>>>> Re-organize into module structure // You'll have to choose an icon size at your own discretion. On X11, the desired size varies // by WM, and on Windows, you still have to account for screen scaling. Here we use 32px, // since it seems to work well enough in most cases. Be careful about going too high, or @@ -20,9 +27,9 @@ fn main() { // feature enabled). let icon = Icon::from_path(path).expect("Failed to open icon"); - let events_loop = winit::EventLoop::new(); + let events_loop = EventLoop::new(); - let window = winit::WindowBuilder::new() + let window = WindowBuilder::new() .with_title("An iconic window!") // At present, this only does anything on Windows and X11, so if you want to save load // time, you can put icon loading behind a function that returns `None` on other platforms. @@ -31,11 +38,11 @@ fn main() { .unwrap(); events_loop.run(move |event, _, control_flow| { - *control_flow = winit::ControlFlow::Wait; - if let winit::Event::WindowEvent { event, .. } = event { - use winit::WindowEvent::*; + *control_flow = ControlFlow::Wait; + if let Event::WindowEvent { event, .. } = event { + use winit::event::WindowEvent::*; match event { - CloseRequested => *control_flow = winit::ControlFlow::Exit, + CloseRequested => *control_flow = ControlFlow::Exit, DroppedFile(path) => { use image::GenericImageView; diff --git a/src/events.rs b/src/event.rs similarity index 96% rename from src/events.rs rename to src/event.rs index dab2d7d06e..ad73473d6a 100644 --- a/src/events.rs +++ b/src/event.rs @@ -1,7 +1,9 @@ use std::time::Instant; use std::path::PathBuf; -use {DeviceId, LogicalPosition, LogicalSize, WindowId}; +use dpi::{LogicalPosition, LogicalSize}; +use window::WindowId; +use platform_impl; /// Describes a generic event. #[derive(Clone, Debug, PartialEq)] @@ -158,6 +160,14 @@ pub enum WindowEvent { HiDpiFactorChanged(f64), } +/// Identifier of an input device. +/// +/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which +/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or +/// physical. Virtual devices typically aggregate inputs from multiple physical devices. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct DeviceId(pub(crate) platform_impl::DeviceId); + /// Represents raw hardware events that are not associated with any particular window. /// /// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera or first-person diff --git a/src/event_loop.rs b/src/event_loop.rs new file mode 100644 index 0000000000..3870c70a88 --- /dev/null +++ b/src/event_loop.rs @@ -0,0 +1,151 @@ +use std::{fmt, error}; +use std::time::Instant; + +use platform_impl; +use event::Event; +use monitor::{AvailableMonitorsIter, MonitorId}; + +/// Provides a way to retrieve events from the system and from the windows that were registered to +/// the events loop. +/// +/// An `EventLoop` can be seen more or less as a "context". Calling `EventLoop::new()` +/// initializes everything that will be required to create windows. For example on Linux creating +/// an events loop opens a connection to the X or Wayland server. +/// +/// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs. +/// +/// Note that the `EventLoop` cannot be shared accross threads (due to platform-dependant logic +/// forbiding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the +/// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the +/// `EventLoopProxy` allows you to wakeup an `EventLoop` from an other thread. +pub struct EventLoop { + pub(crate) events_loop: platform_impl::EventLoop, + pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync +} + +impl std::fmt::Debug for EventLoop { + fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { + fmtr.pad("EventLoop { .. }") + } +} + +/// Returned by the user callback given to the `EventLoop::run_forever` method. +/// +/// Indicates whether the `run_forever` method should continue or complete. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum ControlFlow { + /// When the current loop iteration finishes, suspend the thread until another event arrives. + Wait, + /// When the current loop iteration finishes, suspend the thread until either another event + /// arrives or the given time is reached. + WaitUntil(Instant), + /// When the current loop iteration finishes, immediately begin a new iteration regardless of + /// whether or not new events are available to process. + Poll, + /// Send a `LoopDestroyed` event and stop the event loop. + Exit +} + +impl Default for ControlFlow { + #[inline(always)] + fn default() -> ControlFlow { + ControlFlow::Poll + } +} + +impl EventLoop<()> { + pub fn new() -> EventLoop<()> { + EventLoop::<()>::new_user_event() + } +} + +impl EventLoop { + /// Builds a new events loop. + /// + /// Usage will result in display backend initialisation, this can be controlled on linux + /// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`. + /// If it is not set, winit will try to connect to a wayland connection, and if it fails will + /// fallback on x11. If this variable is set with any other value, winit will panic. + pub fn new_user_event() -> EventLoop { + EventLoop { + events_loop: platform_impl::EventLoop::new(), + _marker: ::std::marker::PhantomData, + } + } + + /// Returns the list of all the monitors available on the system. + /// + // Note: should be replaced with `-> impl Iterator` once stable. + #[inline] + pub fn get_available_monitors(&self) -> AvailableMonitorsIter { + let data = self.events_loop.get_available_monitors(); + AvailableMonitorsIter{ data: data.into_iter() } + } + + /// Returns the primary monitor of the system. + #[inline] + pub fn get_primary_monitor(&self) -> MonitorId { + MonitorId { inner: self.events_loop.get_primary_monitor() } + } + + /// Hijacks the calling thread and initializes the `winit` event loop. Can take a + /// `FnMut(Event, &EventLoop) -> ControlFlow` or a custom `EventHandler` type. + /// + /// Any values not passed to this function will *not* be dropped. + #[inline] + pub fn run(self, event_handler: F) -> ! + where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow) + { + self.events_loop.run(event_handler) + } + + /// Creates an `EventLoopProxy` that can be used to wake up the `EventLoop` from another + /// thread. + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { + events_loop_proxy: self.events_loop.create_proxy(), + } + } +} + +/// Used to wake up the `EventLoop` from another thread. +#[derive(Clone)] +pub struct EventLoopProxy { + events_loop_proxy: platform_impl::EventLoopProxy, +} + +impl EventLoopProxy { + /// Send an event to the `EventLoop` from which this proxy was created. This emits a + /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this + /// function. + /// + /// Returns an `Err` if the associated `EventLoop` no longer exists. + pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { + self.events_loop_proxy.send_event(event) + } +} + +impl std::fmt::Debug for EventLoopProxy { + fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { + fmtr.pad("EventLoopProxy { .. }") + } +} + +/// The error that is returned when an `EventLoopProxy` attempts to wake up an `EventLoop` that +/// no longer exists. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct EventLoopClosed; + +impl fmt::Display for EventLoopClosed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", error::Error::description(self)) + } +} + +impl error::Error for EventLoopClosed { + fn description(&self) -> &str { + "Tried to wake up a closed `EventLoop`" + } +} + diff --git a/src/lib.rs b/src/lib.rs index a06315cf30..d814170b4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ //! `EventLoop::new()` function. Example: //! //! ```no_run -//! use winit::EventLoop; +//! use winit::event_loop::EventLoop; //! let events_loop = EventLoop::new(); //! ``` //! @@ -32,8 +32,9 @@ //! stopped by returning `ControlFlow::Exit`, at which point the entire program will terminate. //! //! ```no_run -//! use winit::{ControlFlow, Event, WindowEvent}; -//! # use winit::EventLoop; +//! use winit::event_loop::ControlFlow; +//! use winit::event::{Event, WindowEvent}; +//! # use winit::event_loop::EventLoop; //! # let events_loop = EventLoop::new(); //! //! events_loop.run(move |event, _, control_flow| { @@ -54,7 +55,7 @@ //! # Drawing on the window //! //! Winit doesn't provide any function that allows drawing on a window. However it allows you to -//! retrieve the raw handle of the window (see the `os` module for that), which in turn allows you +//! retrieve the raw handle of the window (see the `platform` module for that), which in turn allows you //! to create an OpenGL/Vulkan/DirectX/Metal/etc. context that will draw on the window. //! @@ -93,407 +94,12 @@ extern crate percent_encoding; #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] extern crate smithay_client_toolkit as sctk; -use std::time::Instant; -pub(crate) use dpi::*; // TODO: Actually change the imports throughout the codebase. -pub use events::*; -pub use window::{AvailableMonitorsIter, MonitorId}; -pub use icon::*; - pub mod dpi; -mod events; +pub mod event; +pub mod event_loop; mod icon; mod platform_impl; -mod window; +pub mod window; +pub mod monitor; pub mod platform; - -/// Represents a window. -/// -/// # Example -/// -/// ```no_run -/// use winit::{Event, EventLoop, Window, WindowEvent, ControlFlow}; -/// -/// let mut events_loop = EventLoop::new(); -/// let window = Window::new(&events_loop).unwrap(); -/// -/// events_loop.run(move |event, _, control_flow| { -/// match event { -/// Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { -/// *control_flow = ControlFlow::Exit -/// }, -/// _ => *control_flow = ControlFlow::Wait, -/// } -/// }); -/// ``` -pub struct Window { - window: platform_impl::Window, -} - -impl std::fmt::Debug for Window { - fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { - fmtr.pad("Window { .. }") - } -} - -/// Identifier of a window. Unique for each window. -/// -/// Can be obtained with `window.id()`. -/// -/// Whenever you receive an event specific to a window, this event contains a `WindowId` which you -/// can then compare to the ids of your windows. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct WindowId(platform_impl::WindowId); - -/// Identifier of an input device. -/// -/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which -/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or -/// physical. Virtual devices typically aggregate inputs from multiple physical devices. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct DeviceId(platform_impl::DeviceId); - -/// Provides a way to retrieve events from the system and from the windows that were registered to -/// the events loop. -/// -/// An `EventLoop` can be seen more or less as a "context". Calling `EventLoop::new()` -/// initializes everything that will be required to create windows. For example on Linux creating -/// an events loop opens a connection to the X or Wayland server. -/// -/// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs. -/// -/// Note that the `EventLoop` cannot be shared accross threads (due to platform-dependant logic -/// forbiding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the -/// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the -/// `EventLoopProxy` allows you to wakeup an `EventLoop` from an other thread. -pub struct EventLoop { - events_loop: platform_impl::EventLoop, - _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync -} - -impl std::fmt::Debug for EventLoop { - fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { - fmtr.pad("EventLoop { .. }") - } -} - -/// Returned by the user callback given to the `EventLoop::run_forever` method. -/// -/// Indicates whether the `run_forever` method should continue or complete. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum ControlFlow { - /// When the current loop iteration finishes, suspend the thread until another event arrives. - Wait, - /// When the current loop iteration finishes, suspend the thread until either another event - /// arrives or the given time is reached. - WaitUntil(Instant), - /// When the current loop iteration finishes, immediately begin a new iteration regardless of - /// whether or not new events are available to process. - Poll, - /// Send a `LoopDestroyed` event and stop the event loop. - Exit -} - -impl Default for ControlFlow { - #[inline(always)] - fn default() -> ControlFlow { - ControlFlow::Poll - } -} - -impl EventLoop<()> { - pub fn new() -> EventLoop<()> { - EventLoop::<()>::new_user_event() - } -} - -impl EventLoop { - /// Builds a new events loop. - /// - /// Usage will result in display backend initialisation, this can be controlled on linux - /// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`. - /// If it is not set, winit will try to connect to a wayland connection, and if it fails will - /// fallback on x11. If this variable is set with any other value, winit will panic. - pub fn new_user_event() -> EventLoop { - EventLoop { - events_loop: platform_impl::EventLoop::new(), - _marker: ::std::marker::PhantomData, - } - } - - /// Returns the list of all the monitors available on the system. - /// - // Note: should be replaced with `-> impl Iterator` once stable. - #[inline] - pub fn get_available_monitors(&self) -> AvailableMonitorsIter { - let data = self.events_loop.get_available_monitors(); - AvailableMonitorsIter{ data: data.into_iter() } - } - - /// Returns the primary monitor of the system. - #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId { inner: self.events_loop.get_primary_monitor() } - } - - /// Hijacks the calling thread and initializes the `winit` event loop. Can take a - /// `FnMut(Event, &EventLoop) -> ControlFlow` or a custom `EventHandler` type. - /// - /// Any values not passed to this function will *not* be dropped. - #[inline] - pub fn run(self, event_handler: F) -> ! - where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow) - { - self.events_loop.run(event_handler) - } - - /// Creates an `EventLoopProxy` that can be used to wake up the `EventLoop` from another - /// thread. - pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy { - events_loop_proxy: self.events_loop.create_proxy(), - } - } -} - -/// Used to wake up the `EventLoop` from another thread. -#[derive(Clone)] -pub struct EventLoopProxy { - events_loop_proxy: platform_impl::EventLoopProxy, -} - -impl std::fmt::Debug for EventLoopProxy { - fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { - fmtr.pad("EventLoopProxy { .. }") - } -} - -impl EventLoopProxy { - /// Send an event to the `EventLoop` from which this proxy was created. This emits a - /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this - /// function. - /// - /// Returns an `Err` if the associated `EventLoop` no longer exists. - pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { - self.events_loop_proxy.send_event(event) - } -} - -/// The error that is returned when an `EventLoopProxy` attempts to wake up an `EventLoop` that -/// no longer exists. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct EventLoopClosed; - -impl std::fmt::Display for EventLoopClosed { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", std::error::Error::description(self)) - } -} - -impl std::error::Error for EventLoopClosed { - fn description(&self) -> &str { - "Tried to wake up a closed `EventLoop`" - } -} - -/// Object that allows you to build windows. -#[derive(Clone)] -pub struct WindowBuilder { - /// The attributes to use to create the window. - pub window: WindowAttributes, - - // Platform-specific configuration. Private. - platform_specific: platform_impl::PlatformSpecificWindowBuilderAttributes, -} - -impl std::fmt::Debug for WindowBuilder { - fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { - fmtr.debug_struct("WindowBuilder") - .field("window", &self.window) - .finish() - } -} - -/// Error that can happen while creating a window or a headless renderer. -#[derive(Debug, Clone)] -pub enum CreationError { - OsError(String), - /// TODO: remove this error - NotSupported, -} - -impl CreationError { - fn to_string(&self) -> &str { - match *self { - CreationError::OsError(ref text) => &text, - CreationError::NotSupported => "Some of the requested attributes are not supported", - } - } -} - -impl std::fmt::Display for CreationError { - fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - formatter.write_str(self.to_string()) - } -} - -impl std::error::Error for CreationError { - fn description(&self) -> &str { - self.to_string() - } -} - -/// Describes the appearance of the mouse cursor. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum MouseCursor { - /// The platform-dependent default cursor. - Default, - /// A simple crosshair. - Crosshair, - /// A hand (often used to indicate links in web browsers). - Hand, - /// Self explanatory. - Arrow, - /// Indicates something is to be moved. - Move, - /// Indicates text that may be selected or edited. - Text, - /// Program busy indicator. - Wait, - /// Help indicator (often rendered as a "?") - Help, - /// Progress indicator. Shows that processing is being done. But in contrast - /// with "Wait" the user may still interact with the program. Often rendered - /// as a spinning beach ball, or an arrow with a watch or hourglass. - Progress, - - /// Cursor showing that something cannot be done. - NotAllowed, - ContextMenu, - Cell, - VerticalText, - Alias, - Copy, - NoDrop, - Grab, - Grabbing, - AllScroll, - ZoomIn, - ZoomOut, - - /// Indicate that some edge is to be moved. For example, the 'SeResize' cursor - /// is used when the movement starts from the south-east corner of the box. - EResize, - NResize, - NeResize, - NwResize, - SResize, - SeResize, - SwResize, - WResize, - EwResize, - NsResize, - NeswResize, - NwseResize, - ColResize, - RowResize, -} - -impl Default for MouseCursor { - fn default() -> Self { - MouseCursor::Default - } -} - -/// Attributes to use when creating a window. -#[derive(Debug, Clone)] -pub struct WindowAttributes { - /// The dimensions of the window. If this is `None`, some platform-specific dimensions will be - /// used. - /// - /// The default is `None`. - pub dimensions: Option, - - /// The minimum dimensions a window can be, If this is `None`, the window will have no minimum dimensions (aside from reserved). - /// - /// The default is `None`. - pub min_dimensions: Option, - - /// The maximum dimensions a window can be, If this is `None`, the maximum will have no maximum or will be set to the primary monitor's dimensions by the platform. - /// - /// The default is `None`. - pub max_dimensions: Option, - - /// Whether the window is resizable or not. - /// - /// The default is `true`. - pub resizable: bool, - - /// Whether the window should be set as fullscreen upon creation. - /// - /// The default is `None`. - pub fullscreen: Option, - - /// The title of the window in the title bar. - /// - /// The default is `"winit window"`. - pub title: String, - - /// Whether the window should be maximized upon creation. - /// - /// The default is `false`. - pub maximized: bool, - - /// Whether the window should be immediately visible upon creation. - /// - /// The default is `true`. - pub visible: bool, - - /// Whether the the window should be transparent. If this is true, writing colors - /// with alpha values different than `1.0` will produce a transparent window. - /// - /// The default is `false`. - pub transparent: bool, - - /// Whether the window should have borders and bars. - /// - /// The default is `true`. - pub decorations: bool, - - /// Whether the window should always be on top of other windows. - /// - /// The default is `false`. - pub always_on_top: bool, - - /// The window icon. - /// - /// The default is `None`. - pub window_icon: Option, - - /// [iOS only] Enable multitouch, - /// see [multipleTouchEnabled](https://developer.apple.com/documentation/uikit/uiview/1622519-multipletouchenabled) - pub multitouch: bool, -} - -impl Default for WindowAttributes { - #[inline] - fn default() -> WindowAttributes { - WindowAttributes { - dimensions: None, - min_dimensions: None, - max_dimensions: None, - resizable: true, - title: "winit window".to_owned(), - maximized: false, - fullscreen: None, - visible: true, - transparent: false, - decorations: true, - always_on_top: false, - window_icon: None, - multitouch: false, - } - } -} diff --git a/src/monitor.rs b/src/monitor.rs new file mode 100644 index 0000000000..4697b1f844 --- /dev/null +++ b/src/monitor.rs @@ -0,0 +1,68 @@ +use std::collections::vec_deque::IntoIter as VecDequeIter; + +use platform_impl; +use dpi::{PhysicalPosition, PhysicalSize}; + +/// An iterator for the list of available monitors. +// Implementation note: we retrieve the list once, then serve each element by one by one. +// This may change in the future. +#[derive(Debug)] +pub struct AvailableMonitorsIter { + pub(crate) data: VecDequeIter, +} + +impl Iterator for AvailableMonitorsIter { + type Item = MonitorId; + + #[inline] + fn next(&mut self) -> Option { + self.data.next().map(|id| MonitorId { inner: id }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.data.size_hint() + } +} + +/// Identifier for a monitor. +#[derive(Debug, Clone)] +pub struct MonitorId { + pub(crate) inner: platform_impl::MonitorId +} + +impl MonitorId { + /// Returns a human-readable name of the monitor. + /// + /// Returns `None` if the monitor doesn't exist anymore. + #[inline] + pub fn get_name(&self) -> Option { + self.inner.get_name() + } + + /// Returns the monitor's resolution. + #[inline] + pub fn get_dimensions(&self) -> PhysicalSize { + self.inner.get_dimensions() + } + + /// Returns the top-left corner position of the monitor relative to the larger full + /// screen area. + #[inline] + pub fn get_position(&self) -> PhysicalPosition { + self.inner.get_position() + } + + /// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa. + /// + /// See the [`dpi`](dpi/index.html) module for more information. + /// + /// ## Platform-specific + /// + /// - **X11:** Can be overridden using the `WINIT_HIDPI_FACTOR` environment variable. + /// - **Android:** Always returns 1.0. + #[inline] + pub fn get_hidpi_factor(&self) -> f64 { + self.inner.get_hidpi_factor() + } +} diff --git a/src/platform/desktop.rs b/src/platform/desktop.rs index 5ab9be6668..51da320107 100644 --- a/src/platform/desktop.rs +++ b/src/platform/desktop.rs @@ -4,7 +4,8 @@ target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd" ))] -use {EventLoop, Event, ControlFlow}; +use event::Event; +use event_loop::{EventLoop, ControlFlow}; /// Additional methods on `EventLoop` that are specific to desktop platforms. pub trait EventLoopExtDesktop { diff --git a/src/platform/windows.rs b/src/platform/windows.rs index b792d9aa85..3a4e08bab6 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -5,7 +5,10 @@ use std::os::raw::c_void; use libc; use winapi::shared::windef::HWND; -use {DeviceId, EventLoop, Icon, MonitorId, Window, WindowBuilder}; +use event::DeviceId; +use monitor::MonitorId; +use event_loop::EventLoop; +use window::{Icon, Window, WindowBuilder}; use platform_impl::EventLoop as WindowsEventLoop; /// Additional methods on `EventLoop` that are specific to Windows. diff --git a/src/platform_impl/windows/drop_handler.rs b/src/platform_impl/windows/drop_handler.rs index 0d94c12348..188d7be0c0 100644 --- a/src/platform_impl/windows/drop_handler.rs +++ b/src/platform_impl/windows/drop_handler.rs @@ -17,7 +17,8 @@ use winapi::um::{shellapi, unknwnbase}; use platform_impl::platform::WindowId; -use {Event, WindowId as SuperWindowId}; +use event::Event; +use window::WindowId as SuperWindowId; #[repr(C)] pub struct FileDropHandlerData { @@ -81,7 +82,7 @@ impl FileDropHandler { _pt: *const POINTL, _pdwEffect: *mut DWORD, ) -> HRESULT { - use events::WindowEvent::HoveredFile; + use event::WindowEvent::HoveredFile; let drop_handler = Self::from_interface(this); Self::iterate_filenames(pDataObj, |filename| { drop_handler.send_event(Event::WindowEvent { @@ -103,7 +104,7 @@ impl FileDropHandler { } pub unsafe extern "system" fn DragLeave(this: *mut IDropTarget) -> HRESULT { - use events::WindowEvent::HoveredFileCancelled; + use event::WindowEvent::HoveredFileCancelled; let drop_handler = Self::from_interface(this); drop_handler.send_event(Event::WindowEvent { window_id: SuperWindowId(WindowId(drop_handler.window)), @@ -120,7 +121,7 @@ impl FileDropHandler { _pt: *const POINTL, _pdwEffect: *mut DWORD, ) -> HRESULT { - use events::WindowEvent::DroppedFile; + use event::WindowEvent::DroppedFile; let drop_handler = Self::from_interface(this); let hdrop = Self::iterate_filenames(pDataObj, |filename| { drop_handler.send_event(Event::WindowEvent { diff --git a/src/platform_impl/windows/event.rs b/src/platform_impl/windows/event.rs index dfdff6ee63..60e1b910f8 100644 --- a/src/platform_impl/windows/event.rs +++ b/src/platform_impl/windows/event.rs @@ -1,14 +1,11 @@ use std::char; use std::os::raw::c_int; -use events::VirtualKeyCode; -use events::ModifiersState; +use event::{ScanCode, ModifiersState, VirtualKeyCode}; use winapi::shared::minwindef::{WPARAM, LPARAM, UINT}; use winapi::um::winuser; -use ScanCode; - pub fn get_key_mods() -> ModifiersState { let mut mods = ModifiersState::default(); unsafe { diff --git a/src/platform_impl/windows/events_loop.rs b/src/platform_impl/windows/events_loop.rs index dba70c0591..5cafe32d04 100644 --- a/src/platform_impl/windows/events_loop.rs +++ b/src/platform_impl/windows/events_loop.rs @@ -40,18 +40,11 @@ use winapi::shared::windowsx; use winapi::um::{winuser, winbase, ole2, processthreadsapi, commctrl, libloaderapi}; use winapi::um::winnt::{LONG, LPCSTR, SHORT}; -use { - ControlFlow, - Event, - EventLoopClosed, - KeyboardInput, - LogicalPosition, - LogicalSize, - PhysicalSize, - WindowEvent, - WindowId as SuperWindowId, -}; -use events::{DeviceEvent, Touch, TouchPhase, StartCause}; +use window::WindowId as RootWindowId; +use monitor::MonitorId; +use event_loop::{ControlFlow, EventLoop as RootEventLoop, EventLoopClosed}; +use dpi::{LogicalPosition, LogicalSize, PhysicalSize}; +use event::{DeviceEvent, Touch, TouchPhase, StartCause, KeyboardInput, Event, WindowEvent}; use platform_impl::platform::{event, Cursor, WindowId, DEVICE_ID, wrap_device_id, util}; use platform_impl::platform::dpi::{ become_dpi_aware, @@ -98,7 +91,7 @@ pub struct WindowState { // This is different from the value in `SavedWindowInfo`! That one represents the DPI saved upon entering // fullscreen. This will always be the most recent DPI for the window. pub dpi_factor: f64, - pub fullscreen: Option<::MonitorId>, + pub fullscreen: Option, pub window_icon: Option, pub taskbar_icon: Option, pub decorations: bool, @@ -183,14 +176,14 @@ impl EventLoop { } pub fn run(mut self, event_handler: F) -> ! - where F: 'static + FnMut(Event, &::EventLoop, &mut ControlFlow) + where F: 'static + FnMut(Event, &RootEventLoop, &mut ControlFlow) { self.run_return(event_handler); ::std::process::exit(0); } pub fn run_return(&mut self, mut event_handler: F) - where F: FnMut(Event, &::EventLoop, &mut ControlFlow) + where F: FnMut(Event, &RootEventLoop, &mut ControlFlow) { unsafe{ winuser::IsGUIThread(1); } let mut runner = EventLoopRunner { @@ -201,8 +194,8 @@ impl EventLoop { event_handler: unsafe { // Transmute used to erase lifetimes. mem::transmute::< - &mut FnMut(Event, &::EventLoop, &mut ControlFlow), - *mut FnMut(Event, &::EventLoop, &mut ControlFlow) + &mut FnMut(Event, &RootEventLoop, &mut ControlFlow), + *mut FnMut(Event, &RootEventLoop, &mut ControlFlow) >(&mut event_handler) } }; @@ -294,7 +287,7 @@ pub(crate) struct EventLoopRunner { control_flow: ControlFlow, runner_state: RunnerState, modal_loop_data: Option, - event_handler: *mut FnMut(Event, &::EventLoop, &mut ControlFlow) + event_handler: *mut FnMut(Event, &RootEventLoop, &mut ControlFlow) } struct ModalLoopData { @@ -468,8 +461,8 @@ impl EventLoopRunner { _ => () } - assert_eq!(mem::size_of::<::EventLoop>(), mem::size_of::>()); - let event_loop_ref = &*(self.event_loop as *const ::EventLoop); + assert_eq!(mem::size_of::>(), mem::size_of::>()); + let event_loop_ref = &*(self.event_loop as *const RootEventLoop); if self.control_flow != ControlFlow::Exit { (*self.event_handler)(event, event_loop_ref, &mut self.control_flow); @@ -800,16 +793,16 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_CLOSE => { - use events::WindowEvent::CloseRequested; + use event::WindowEvent::CloseRequested; subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: CloseRequested }); 0 }, winuser::WM_DESTROY => { - use events::WindowEvent::Destroyed; + use event::WindowEvent::Destroyed; ole2::RevokeDragDrop(window); { let window_state = subclass_input.window_state.lock(); @@ -818,7 +811,7 @@ unsafe extern "system" fn public_window_callback( } } subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: Destroyed }); @@ -828,14 +821,14 @@ unsafe extern "system" fn public_window_callback( }, _ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => { - use events::WindowEvent::RedrawRequested; + use event::WindowEvent::RedrawRequested; let runner = subclass_input.event_loop_runner.borrow_mut(); if let ELRSharedOption::Runner(runner) = *runner { let runner = &mut *runner; match runner.runner_state { RunnerState::Idle(..) | RunnerState::DeferredNewEvents(..) => runner.call_event_handler(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: RedrawRequested, }), _ => () @@ -844,9 +837,9 @@ unsafe extern "system" fn public_window_callback( 0 }, winuser::WM_PAINT => { - use events::WindowEvent::RedrawRequested; + use event::WindowEvent::RedrawRequested; let event = || Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: RedrawRequested, }; @@ -870,7 +863,7 @@ unsafe extern "system" fn public_window_callback( // WM_MOVE supplies client area positions, so we send Moved here instead. winuser::WM_WINDOWPOSCHANGED => { - use events::WindowEvent::Moved; + use event::WindowEvent::Moved; let windowpos = lparam as *const winuser::WINDOWPOS; if (*windowpos).flags & winuser::SWP_NOMOVE != winuser::SWP_NOMOVE { @@ -880,7 +873,7 @@ unsafe extern "system" fn public_window_callback( dpi_factor, ); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: Moved(logical_position), }); } @@ -890,14 +883,14 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_SIZE => { - use events::WindowEvent::Resized; + use event::WindowEvent::Resized; let w = LOWORD(lparam as DWORD) as u32; let h = HIWORD(lparam as DWORD) as u32; let dpi_factor = get_hwnd_scale_factor(window); let logical_size = LogicalSize::from_physical((w, h), dpi_factor); let event = Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: Resized(logical_size), }; @@ -907,10 +900,10 @@ unsafe extern "system" fn public_window_callback( winuser::WM_CHAR => { use std::mem; - use events::WindowEvent::ReceivedCharacter; + use event::WindowEvent::ReceivedCharacter; let chr: char = mem::transmute(wparam as u32); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: ReceivedCharacter(chr), }); 0 @@ -925,7 +918,7 @@ unsafe extern "system" fn public_window_callback( } winuser::WM_MOUSEMOVE => { - use events::WindowEvent::{CursorEntered, CursorMoved}; + use event::WindowEvent::{CursorEntered, CursorMoved}; let mouse_outside_window = { let mut window = subclass_input.window_state.lock(); if !window.mouse_in_window { @@ -938,7 +931,7 @@ unsafe extern "system" fn public_window_callback( if mouse_outside_window { subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: CursorEntered { device_id: DEVICE_ID }, }); @@ -957,7 +950,7 @@ unsafe extern "system" fn public_window_callback( let position = LogicalPosition::from_physical((x, y), dpi_factor); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() }, }); @@ -965,7 +958,7 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_MOUSELEAVE => { - use events::WindowEvent::CursorLeft; + use event::WindowEvent::CursorLeft; let mouse_in_window = { let mut window = subclass_input.window_state.lock(); if window.mouse_in_window { @@ -978,7 +971,7 @@ unsafe extern "system" fn public_window_callback( if mouse_in_window { subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: CursorLeft { device_id: DEVICE_ID } }); } @@ -987,15 +980,15 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_MOUSEWHEEL => { - use events::MouseScrollDelta::LineDelta; - use events::TouchPhase; + use event::MouseScrollDelta::LineDelta; + use event::TouchPhase; let value = (wparam >> 16) as i16; let value = value as i32; let value = value as f32 / winuser::WHEEL_DELTA as f32; subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved, modifiers: event::get_key_mods() }, }); @@ -1003,14 +996,14 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN => { - use events::ElementState::Pressed; - use events::VirtualKeyCode; + use event::ElementState::Pressed; + use event::VirtualKeyCode; if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 { commctrl::DefSubclassProc(window, msg, wparam, lparam) } else { if let Some((scancode, vkey)) = process_key_params(wparam, lparam) { subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: WindowEvent::KeyboardInput { device_id: DEVICE_ID, input: KeyboardInput { @@ -1025,7 +1018,7 @@ unsafe extern "system" fn public_window_callback( // consistent with the other platforms we'll emit a delete character here. if vkey == Some(VirtualKeyCode::Delete) { subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: WindowEvent::ReceivedCharacter('\u{7F}'), }); } @@ -1035,10 +1028,10 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_KEYUP | winuser::WM_SYSKEYUP => { - use events::ElementState::Released; + use event::ElementState::Released; if let Some((scancode, vkey)) = process_key_params(wparam, lparam) { subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: WindowEvent::KeyboardInput { device_id: DEVICE_ID, input: KeyboardInput { @@ -1054,114 +1047,114 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_LBUTTONDOWN => { - use events::WindowEvent::MouseInput; - use events::MouseButton::Left; - use events::ElementState::Pressed; + use event::WindowEvent::MouseInput; + use event::MouseButton::Left; + use event::ElementState::Pressed; capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() } }); 0 }, winuser::WM_LBUTTONUP => { - use events::WindowEvent::MouseInput; - use events::MouseButton::Left; - use events::ElementState::Released; + use event::WindowEvent::MouseInput; + use event::MouseButton::Left; + use event::ElementState::Released; release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() } }); 0 }, winuser::WM_RBUTTONDOWN => { - use events::WindowEvent::MouseInput; - use events::MouseButton::Right; - use events::ElementState::Pressed; + use event::WindowEvent::MouseInput; + use event::MouseButton::Right; + use event::ElementState::Pressed; capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() } }); 0 }, winuser::WM_RBUTTONUP => { - use events::WindowEvent::MouseInput; - use events::MouseButton::Right; - use events::ElementState::Released; + use event::WindowEvent::MouseInput; + use event::MouseButton::Right; + use event::ElementState::Released; release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() } }); 0 }, winuser::WM_MBUTTONDOWN => { - use events::WindowEvent::MouseInput; - use events::MouseButton::Middle; - use events::ElementState::Pressed; + use event::WindowEvent::MouseInput; + use event::MouseButton::Middle; + use event::ElementState::Pressed; capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() } }); 0 }, winuser::WM_MBUTTONUP => { - use events::WindowEvent::MouseInput; - use events::MouseButton::Middle; - use events::ElementState::Released; + use event::WindowEvent::MouseInput; + use event::MouseButton::Middle; + use event::ElementState::Released; release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() } }); 0 }, winuser::WM_XBUTTONDOWN => { - use events::WindowEvent::MouseInput; - use events::MouseButton::Other; - use events::ElementState::Pressed; + use event::WindowEvent::MouseInput; + use event::MouseButton::Other; + use event::ElementState::Pressed; let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); capture_mouse(window, &mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() } }); 0 }, winuser::WM_XBUTTONUP => { - use events::WindowEvent::MouseInput; - use events::MouseButton::Other; - use events::ElementState::Released; + use event::WindowEvent::MouseInput; + use event::MouseButton::Other; + use event::ElementState::Released; let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); release_mouse(&mut *subclass_input.window_state.lock()); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() } }); 0 @@ -1183,9 +1176,9 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_INPUT => { - use events::DeviceEvent::{Motion, MouseMotion, MouseWheel, Button, Key}; - use events::MouseScrollDelta::LineDelta; - use events::ElementState::{Pressed, Released}; + use event::DeviceEvent::{Motion, MouseMotion, MouseWheel, Button, Key}; + use event::MouseScrollDelta::LineDelta; + use event::ElementState::{Pressed, Released}; if let Some(data) = get_raw_input_data(lparam as _) { let device_id = wrap_device_id(data.header.hDevice as _); @@ -1303,7 +1296,7 @@ unsafe extern "system" fn public_window_callback( let y = (input.y as f64) / 100f64; let location = LogicalPosition::from_physical((x, y), dpi_factor); subclass_input.send_event( Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: WindowEvent::Touch(Touch { phase: if input.dwFlags & winuser::TOUCHEVENTF_DOWN != 0 { @@ -1327,9 +1320,9 @@ unsafe extern "system" fn public_window_callback( } winuser::WM_SETFOCUS => { - use events::WindowEvent::{Focused, CursorMoved}; + use event::WindowEvent::{Focused, CursorMoved}; subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: Focused(true) }); @@ -1339,7 +1332,7 @@ unsafe extern "system" fn public_window_callback( let position = LogicalPosition::from_physical((x, y), dpi_factor); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() }, }); @@ -1347,9 +1340,9 @@ unsafe extern "system" fn public_window_callback( }, winuser::WM_KILLFOCUS => { - use events::WindowEvent::Focused; + use event::WindowEvent::Focused; subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: Focused(false) }); 0 @@ -1406,7 +1399,7 @@ unsafe extern "system" fn public_window_callback( // Only sent on Windows 8.1 or newer. On Windows 7 and older user has to log out to change // DPI, therefore all applications are closed while DPI is changing. winuser::WM_DPICHANGED => { - use events::WindowEvent::HiDpiFactorChanged; + use event::WindowEvent::HiDpiFactorChanged; // This message actually provides two DPI values - x and y. However MSDN says that // "you only need to use either the X-axis or the Y-axis value when scaling your @@ -1454,7 +1447,7 @@ unsafe extern "system" fn public_window_callback( } subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: HiDpiFactorChanged(new_dpi_factor), }); @@ -1466,10 +1459,10 @@ unsafe extern "system" fn public_window_callback( winuser::DestroyWindow(window); 0 } else if msg == *INITIAL_DPI_MSG_ID { - use events::WindowEvent::HiDpiFactorChanged; + use event::WindowEvent::HiDpiFactorChanged; let scale_factor = dpi_to_scale_factor(wparam as u32); subclass_input.send_event(Event::WindowEvent { - window_id: SuperWindowId(WindowId(window)), + window_id: RootWindowId(WindowId(window)), event: HiDpiFactorChanged(scale_factor), }); // Automatically resize for actual DPI diff --git a/src/platform_impl/windows/icon.rs b/src/platform_impl/windows/icon.rs index fb265c9294..c45bdf6fde 100644 --- a/src/platform_impl/windows/icon.rs +++ b/src/platform_impl/windows/icon.rs @@ -7,7 +7,7 @@ use winapi::shared::minwindef::{BYTE, LPARAM, WPARAM}; use winapi::shared::windef::{HICON, HWND}; use winapi::um::winuser; -use {Pixel, PIXEL_SIZE, Icon}; +use icon::{Pixel, PIXEL_SIZE, Icon}; use platform_impl::platform::util; impl Pixel { diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 0e981e091a..02b18770d5 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -7,10 +7,13 @@ pub use self::events_loop::{EventLoop, EventLoopProxy}; pub use self::monitor::MonitorId; pub use self::window::Window; +use window::Icon; +use event::DeviceId as RootDeviceId; + #[derive(Clone, Default)] pub struct PlatformSpecificWindowBuilderAttributes { pub parent: Option, - pub taskbar_icon: Option<::Icon>, + pub taskbar_icon: Option, pub no_redirection_bitmap: bool, } @@ -37,10 +40,10 @@ impl DeviceId { } // Constant device ID, to be removed when this backend is updated to report real device IDs. -const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId(0)); +const DEVICE_ID: RootDeviceId = RootDeviceId(DeviceId(0)); -fn wrap_device_id(id: u32) -> ::DeviceId { - ::DeviceId(DeviceId(id)) +fn wrap_device_id(id: u32) -> RootDeviceId { + RootDeviceId(DeviceId(id)) } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/src/platform_impl/windows/raw_input.rs b/src/platform_impl/windows/raw_input.rs index 12664435b6..03c26d11d9 100644 --- a/src/platform_impl/windows/raw_input.rs +++ b/src/platform_impl/windows/raw_input.rs @@ -32,7 +32,7 @@ use winapi::um::winuser::{ }; use platform_impl::platform::util; -use events::ElementState; +use event::ElementState; #[allow(dead_code)] pub fn get_raw_input_device_list() -> Option> { diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index aed979a57b..37d1f33865 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -18,16 +18,9 @@ use winapi::um::wingdi::{CreateRectRgn, DeleteObject}; use winapi::um::oleidl::LPDROPTARGET; use winapi::um::winnt::{LONG, LPCWSTR}; -use { - CreationError, - Icon, - LogicalPosition, - LogicalSize, - MonitorId as RootMonitorId, - MouseCursor, - PhysicalSize, - WindowAttributes, -}; +use window::{CreationError, Icon, WindowAttributes, MouseCursor}; +use dpi::{LogicalPosition, LogicalSize, PhysicalSize}; +use monitor::MonitorId as RootMonitorId; use platform_impl::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, WindowId}; use platform_impl::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi}; use platform_impl::platform::events_loop::{self, EventLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}; diff --git a/src/window.rs b/src/window.rs index d80807e802..36652072ec 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,20 +1,160 @@ -use std::collections::vec_deque::IntoIter as VecDequeIter; - -use { - CreationError, - EventLoop, - Icon, - LogicalPosition, - LogicalSize, - MouseCursor, - PhysicalPosition, - PhysicalSize, - platform_impl, - Window, - WindowBuilder, - WindowId, -}; +use std::{fmt, error}; + +use platform_impl; +use event_loop::EventLoop; +use monitor::{AvailableMonitorsIter, MonitorId}; +use dpi::{LogicalPosition, LogicalSize}; + +pub use icon::*; + +/// Represents a window. +/// +/// # Example +/// +/// ```no_run +/// use winit::window::Window; +/// use winit::event::{Event, WindowEvent}; +/// use winit::event_loop::{EventLoop, ControlFlow}; +/// +/// let mut events_loop = EventLoop::new(); +/// let window = Window::new(&events_loop).unwrap(); +/// +/// events_loop.run(move |event, _, control_flow| { +/// match event { +/// Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { +/// *control_flow = ControlFlow::Exit +/// }, +/// _ => *control_flow = ControlFlow::Wait, +/// } +/// }); +/// ``` +pub struct Window { + pub(crate) window: platform_impl::Window, +} + +impl std::fmt::Debug for Window { + fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { + fmtr.pad("Window { .. }") + } +} + +/// Identifier of a window. Unique for each window. +/// +/// Can be obtained with `window.id()`. +/// +/// Whenever you receive an event specific to a window, this event contains a `WindowId` which you +/// can then compare to the ids of your windows. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct WindowId(pub(crate) platform_impl::WindowId); + +/// Object that allows you to build windows. +#[derive(Clone)] +pub struct WindowBuilder { + /// The attributes to use to create the window. + pub window: WindowAttributes, + + // Platform-specific configuration. Private. + pub(crate) platform_specific: platform_impl::PlatformSpecificWindowBuilderAttributes, +} + +impl std::fmt::Debug for WindowBuilder { + fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { + fmtr.debug_struct("WindowBuilder") + .field("window", &self.window) + .finish() + } +} + +/// Attributes to use when creating a window. +#[derive(Debug, Clone)] +pub struct WindowAttributes { + /// The dimensions of the window. If this is `None`, some platform-specific dimensions will be + /// used. + /// + /// The default is `None`. + pub dimensions: Option, + + /// The minimum dimensions a window can be, If this is `None`, the window will have no minimum dimensions (aside from reserved). + /// + /// The default is `None`. + pub min_dimensions: Option, + + /// The maximum dimensions a window can be, If this is `None`, the maximum will have no maximum or will be set to the primary monitor's dimensions by the platform. + /// + /// The default is `None`. + pub max_dimensions: Option, + + /// Whether the window is resizable or not. + /// + /// The default is `true`. + pub resizable: bool, + + /// Whether the window should be set as fullscreen upon creation. + /// + /// The default is `None`. + pub fullscreen: Option, + + /// The title of the window in the title bar. + /// + /// The default is `"winit window"`. + pub title: String, + + /// Whether the window should be maximized upon creation. + /// + /// The default is `false`. + pub maximized: bool, + + /// Whether the window should be immediately visible upon creation. + /// + /// The default is `true`. + pub visible: bool, + + /// Whether the the window should be transparent. If this is true, writing colors + /// with alpha values different than `1.0` will produce a transparent window. + /// + /// The default is `false`. + pub transparent: bool, + + /// Whether the window should have borders and bars. + /// + /// The default is `true`. + pub decorations: bool, + + /// Whether the window should always be on top of other windows. + /// + /// The default is `false`. + pub always_on_top: bool, + + /// The window icon. + /// + /// The default is `None`. + pub window_icon: Option, + /// [iOS only] Enable multitouch, + /// see [multipleTouchEnabled](https://developer.apple.com/documentation/uikit/uiview/1622519-multipletouchenabled) + pub multitouch: bool, +} + +impl Default for WindowAttributes { + #[inline] + fn default() -> WindowAttributes { + WindowAttributes { + dimensions: None, + min_dimensions: None, + max_dimensions: None, + resizable: true, + title: "winit window".to_owned(), + maximized: false, + fullscreen: None, + visible: true, + transparent: false, + decorations: true, + always_on_top: false, + window_icon: None, + multitouch: false, + } + } +} impl WindowBuilder { /// Initializes a new `WindowBuilder` with default values. #[inline] @@ -444,66 +584,94 @@ impl Window { } } -/// An iterator for the list of available monitors. -// Implementation note: we retrieve the list once, then serve each element by one by one. -// This may change in the future. -#[derive(Debug)] -pub struct AvailableMonitorsIter { - pub(crate) data: VecDequeIter, +/// Error that can happen while creating a window or a headless renderer. +#[derive(Debug, Clone)] +pub enum CreationError { + OsError(String), + /// TODO: remove this error + NotSupported, } -impl Iterator for AvailableMonitorsIter { - type Item = MonitorId; - - #[inline] - fn next(&mut self) -> Option { - self.data.next().map(|id| MonitorId { inner: id }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.data.size_hint() +impl CreationError { + fn to_string(&self) -> &str { + match *self { + CreationError::OsError(ref text) => &text, + CreationError::NotSupported => "Some of the requested attributes are not supported", + } } } -/// Identifier for a monitor. -#[derive(Debug, Clone)] -pub struct MonitorId { - pub(crate) inner: platform_impl::MonitorId -} - -impl MonitorId { - /// Returns a human-readable name of the monitor. - /// - /// Returns `None` if the monitor doesn't exist anymore. - #[inline] - pub fn get_name(&self) -> Option { - self.inner.get_name() +impl fmt::Display for CreationError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter.write_str(self.to_string()) } +} - /// Returns the monitor's resolution. - #[inline] - pub fn get_dimensions(&self) -> PhysicalSize { - self.inner.get_dimensions() +impl error::Error for CreationError { + fn description(&self) -> &str { + self.to_string() } +} - /// Returns the top-left corner position of the monitor relative to the larger full - /// screen area. - #[inline] - pub fn get_position(&self) -> PhysicalPosition { - self.inner.get_position() - } +/// Describes the appearance of the mouse cursor. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum MouseCursor { + /// The platform-dependent default cursor. + Default, + /// A simple crosshair. + Crosshair, + /// A hand (often used to indicate links in web browsers). + Hand, + /// Self explanatory. + Arrow, + /// Indicates something is to be moved. + Move, + /// Indicates text that may be selected or edited. + Text, + /// Program busy indicator. + Wait, + /// Help indicator (often rendered as a "?") + Help, + /// Progress indicator. Shows that processing is being done. But in contrast + /// with "Wait" the user may still interact with the program. Often rendered + /// as a spinning beach ball, or an arrow with a watch or hourglass. + Progress, + + /// Cursor showing that something cannot be done. + NotAllowed, + ContextMenu, + Cell, + VerticalText, + Alias, + Copy, + NoDrop, + Grab, + Grabbing, + AllScroll, + ZoomIn, + ZoomOut, + + /// Indicate that some edge is to be moved. For example, the 'SeResize' cursor + /// is used when the movement starts from the south-east corner of the box. + EResize, + NResize, + NeResize, + NwResize, + SResize, + SeResize, + SwResize, + WResize, + EwResize, + NsResize, + NeswResize, + NwseResize, + ColResize, + RowResize, +} - /// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa. - /// - /// See the [`dpi`](dpi/index.html) module for more information. - /// - /// ## Platform-specific - /// - /// - **X11:** Can be overridden using the `WINIT_HIDPI_FACTOR` environment variable. - /// - **Android:** Always returns 1.0. - #[inline] - pub fn get_hidpi_factor(&self) -> f64 { - self.inner.get_hidpi_factor() +impl Default for MouseCursor { + fn default() -> Self { + MouseCursor::Default } } diff --git a/tests/send_objects.rs b/tests/send_objects.rs index 6cb0fe43c9..4e61938c10 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -5,19 +5,19 @@ fn needs_send() {} #[test] fn events_loop_proxy_send() { // ensures that `winit::EventLoopProxy` implements `Send` - needs_send::>(); + needs_send::>(); } #[test] fn window_send() { // ensures that `winit::Window` implements `Send` - needs_send::(); + needs_send::(); } #[test] fn ids_send() { // ensures that the various `..Id` types implement `Send` - needs_send::(); - needs_send::(); - needs_send::(); + needs_send::(); + needs_send::(); + needs_send::(); } diff --git a/tests/sync_object.rs b/tests/sync_object.rs index eb9a06e344..c59cc077fc 100644 --- a/tests/sync_object.rs +++ b/tests/sync_object.rs @@ -5,5 +5,5 @@ fn needs_sync() {} #[test] fn window_sync() { // ensures that `winit::Window` implements `Sync` - needs_sync::(); + needs_sync::(); } From 42e8a0d2cf77af79da082fff7cd29cc8f52d99df Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 23 Aug 2018 19:09:19 -0400 Subject: [PATCH 15/40] Improve documentation --- examples/window_icon.rs | 4 --- src/dpi.rs | 8 +++--- src/event.rs | 12 ++++++++- src/event_loop.rs | 26 +++++++++++++++---- src/lib.rs | 56 ++++++++++++++++++++++++++--------------- src/monitor.rs | 21 +++++++++++++++- src/platform/desktop.rs | 6 +++-- src/platform/mod.rs | 8 ++++-- src/window.rs | 2 ++ 9 files changed, 104 insertions(+), 39 deletions(-) diff --git a/examples/window_icon.rs b/examples/window_icon.rs index 9db3e0f050..545b44c9f6 100644 --- a/examples/window_icon.rs +++ b/examples/window_icon.rs @@ -8,14 +8,10 @@ extern crate image; #[cfg(feature = "icon_loading")] fn main() { -<<<<<<< HEAD - use winit::Icon; -======= use winit::window::{WindowBuilder, Icon}; use winit::event::Event; use winit::event_loop::{EventLoop, ControlFlow}; ->>>>>>> Re-organize into module structure // You'll have to choose an icon size at your own discretion. On X11, the desired size varies // by WM, and on Windows, you still have to account for screen scaling. Here we use 32px, // since it seems to work well enough in most cases. Be careful about going too high, or diff --git a/src/dpi.rs b/src/dpi.rs index 0d1514273f..909c9835dc 100644 --- a/src/dpi.rs +++ b/src/dpi.rs @@ -33,9 +33,9 @@ //! windows. This event is sent any time the DPI factor changes, either because the window moved to another monitor, //! or because the user changed the configuration of their screen. //! - You can also retrieve the DPI factor of a monitor by calling -//! [`MonitorId::get_hidpi_factor`](../struct.MonitorId.html#method.get_hidpi_factor), or the +//! [`MonitorId::get_hidpi_factor`](../monitor/struct.MonitorId.html#method.get_hidpi_factor), or the //! current DPI factor applied to a window by calling -//! [`Window::get_hidpi_factor`](../struct.Window.html#method.get_hidpi_factor), which is roughly equivalent +//! [`Window::get_hidpi_factor`](../window/struct.Window.html#method.get_hidpi_factor), which is roughly equivalent //! to `window.get_current_monitor().get_hidpi_factor()`. //! //! Depending on the platform, the window's actual DPI factor may only be known after @@ -59,9 +59,9 @@ //! //! The window's logical size is conserved across DPI changes, resulting in the physical size changing instead. This //! may be surprising on X11, but is quite standard elsewhere. Physical size changes always produce a -//! [`Resized`](../enum.WindowEvent.html#variant.Resized) event, even on platforms where no resize actually occurs, +//! [`Resized`](../event/enum.WindowEvent.html#variant.Resized) event, even on platforms where no resize actually occurs, //! such as macOS and Wayland. As a result, it's not necessary to separately handle -//! [`HiDpiFactorChanged`](../enum.WindowEvent.html#variant.HiDpiFactorChanged) if you're only listening for size. +//! [`HiDpiFactorChanged`](../event/enum.WindowEvent.html#variant.HiDpiFactorChanged) if you're only listening for size. //! //! Your GPU has no awareness of the concept of logical pixels, and unless you like wasting pixel density, your //! framebuffer's size should be in physical pixels. diff --git a/src/event.rs b/src/event.rs index ad73473d6a..e20230248a 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,3 +1,9 @@ +//! The `Event` enum and assorted supporting types. +//! +//! These are sent to the closure given to [`EventLoop::run(...)`][event_loop_run], where they get +//! processed and used to modify the program state. For more details, see the root-level documentation. +//! +//! [event_loop_run]: ../event_loop/struct.EventLoop.html#method.run use std::time::Instant; use std::path::PathBuf; @@ -8,14 +14,17 @@ use platform_impl; /// Describes a generic event. #[derive(Clone, Debug, PartialEq)] pub enum Event { + /// Emitted when the OS sends an event to a winit window. WindowEvent { window_id: WindowId, event: WindowEvent, }, + /// Emitted when the OS sends an event to a device. DeviceEvent { device_id: DeviceId, event: DeviceEvent, }, + /// Emitted when an event is sent from [`EventLoopProxy::send_event`](../event_loop/struct.EventLoopProxy.html#method.send_event) UserEvent(T), /// Emitted when new events arrive from the OS to be processed. NewEvents(StartCause), @@ -27,7 +36,7 @@ pub enum Event { /// emitted, it is guaranteed to be the last event emitted. LoopDestroyed, - /// The application has been suspended or resumed. + /// Emitted when the application has been suspended or resumed. /// /// The parameter is true if app was suspended, and false if it has been resumed. Suspended(bool), @@ -48,6 +57,7 @@ impl Event { } } +/// Describes the reason the event loop is resuming. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum StartCause { /// Sent if the time specified by `ControlFlow::WaitUntil` has been reached. Contains the diff --git a/src/event_loop.rs b/src/event_loop.rs index 3870c70a88..447738547d 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -1,3 +1,14 @@ +//! The `EventLoop` struct and assorted supporting types, including `ControlFlow`. +//! +//! If you want to send custom events to the event loop, use [`EventLoop::create_proxy()`][create_proxy] +//! to acquire an [`EventLoopProxy`][event_loop_proxy] and call its [`send_event`][send_event] method. +//! +//! See the root-level documentation for information on how to create and use an event loop to +//! handle events. +//! +//! [create_proxy]: ./struct.EventLoop.html#method.create_proxy +//! [event_loop_proxy]: ./struct.EventLoopProxy.html +//! [send_event]: ./struct.EventLoopProxy.html#method.send_event use std::{fmt, error}; use std::time::Instant; @@ -29,9 +40,12 @@ impl std::fmt::Debug for EventLoop { } } -/// Returned by the user callback given to the `EventLoop::run_forever` method. +/// Set by the user callback given to the `EventLoop::run` method. /// -/// Indicates whether the `run_forever` method should continue or complete. +/// Indicates the desired behavior of the event loop after [`Event::EventsCleared`][events_cleared] +/// is emitted. +/// +/// [events_cleared]: ../event/enum.Event.html#variant.EventsCleared #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ControlFlow { @@ -43,7 +57,8 @@ pub enum ControlFlow { /// When the current loop iteration finishes, immediately begin a new iteration regardless of /// whether or not new events are available to process. Poll, - /// Send a `LoopDestroyed` event and stop the event loop. + /// Send a `LoopDestroyed` event and stop the event loop. Once set, `control_flow` cannot be + /// changed from `Exit`. Exit } @@ -55,13 +70,14 @@ impl Default for ControlFlow { } impl EventLoop<()> { + /// Builds a new event loop with a `()` as the user event type. pub fn new() -> EventLoop<()> { EventLoop::<()>::new_user_event() } } impl EventLoop { - /// Builds a new events loop. + /// Builds a new event loop. /// /// Usage will result in display backend initialisation, this can be controlled on linux /// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`. @@ -109,7 +125,7 @@ impl EventLoop { } } -/// Used to wake up the `EventLoop` from another thread. +/// Used to send custom events to `EventLoop`. #[derive(Clone)] pub struct EventLoopProxy { events_loop_proxy: platform_impl::EventLoopProxy, diff --git a/src/lib.rs b/src/lib.rs index d814170b4f..69a1db0e66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,34 +2,35 @@ //! //! # Building a window //! -//! Before you can build a window, you first need to build an `EventLoop`. This is done with the -//! `EventLoop::new()` function. Example: +//! Before you can build a [`Window`], you first need to build an [`EventLoop`]. This is done with the +//! [`EventLoop::new()`] function. //! //! ```no_run //! use winit::event_loop::EventLoop; //! let events_loop = EventLoop::new(); //! ``` //! -//! Once this is done there are two ways to create a window: +//! Once this is done there are two ways to create a [`Window`]: //! -//! - Calling `Window::new(&events_loop)`. -//! - Calling `let builder = WindowBuilder::new()` then `builder.build(&events_loop)`. +//! - Calling [`Window::new(&events_loop)`][window_new]. +//! - Calling [`let builder = WindowBuilder::new()`][window_builder_new] then [`builder.build(&events_loop)`][window_builder_build]. //! //! The first way is the simplest way and will give you default values for everything. //! -//! The second way allows you to customize the way your window will look and behave by modifying -//! the fields of the `WindowBuilder` object before you create the window. +//! The second way allows you to customize the way your [`Window`] will look and behave by modifying +//! the fields of the [`WindowBuilder`] object before you create the [`Window`]. //! -//! # Events handling +//! # Event handling //! -//! Once a window has been created, it will *generate events*. For example whenever the user moves -//! the window, resizes the window, moves the mouse, etc. an event is generated. +//! Once a [`Window`] has been created, it will *generate events*. For example whenever the user moves +//! the [`Window`], resizes the [`Window`], moves the mouse, etc. an event is generated. //! -//! The events generated by a window can be retreived from the `EventLoop` the window was created +//! The events generated by a [`Window`] can be retreived from the [`EventLoop`] the [`Window`] was created //! with. //! -//! You do this by calling `events_loop.run(...)`. This function will run forever unless it is -//! stopped by returning `ControlFlow::Exit`, at which point the entire program will terminate. +//! You do this by calling [`events_loop.run(...)`][event_loop_run]. This function will run forever +//! unless `control_flow` is set to [`ControlFlow`]`::`[`Exit`], at which point [`Event`]`::`[`LoopDestroyed`] +//! is emitted and the entire program terminates. //! //! ```no_run //! use winit::event_loop::ControlFlow; @@ -48,16 +49,31 @@ //! }); //! ``` //! -//! If you use multiple windows, the `WindowEvent` event has a member named `window_id`. You can -//! compare it with the value returned by the `id()` method of `Window` in order to know which -//! window has received the event. +//! If you use multiple [`Window`]s, [`Event`]`::`[`WindowEvent`] has a member named `window_id`. You can +//! compare it with the value returned by the [`id()`][window_id_fn] method of [`Window`] in order to know which +//! [`Window`] has received the event. //! //! # Drawing on the window //! -//! Winit doesn't provide any function that allows drawing on a window. However it allows you to -//! retrieve the raw handle of the window (see the `platform` module for that), which in turn allows you -//! to create an OpenGL/Vulkan/DirectX/Metal/etc. context that will draw on the window. -//! +//! Winit doesn't provide any function that allows drawing on a [`Window`]. However it allows you to +//! retrieve the raw handle of the window (see the [`platform`] module), which in turn allows you +//! to create an OpenGL/Vulkan/DirectX/Metal/etc. context that will draw on the [`Window`]. +//! +//! [`EventLoop`]: ./event_loop/struct.EventLoop.html +//! [`EventLoop::new()`]: ./event_loop/struct.EventLoop.html#method.new +//! [event_loop_run]: ./event_loop/struct.EventLoop.html#method.run +//! [`ControlFlow`]: ./event_loop/enum.ControlFlow.html +//! [`Exit`]: ./event_loop/enum.ControlFlow.html#variant.Exit +//! [`Window`]: ./window/struct.Window.html +//! [`WindowBuilder`]: ./window/struct.WindowBuilder.html +//! [window_new]: ./window/struct.Window.html#method.new +//! [window_builder_new]: ./window/struct.WindowBuilder.html#method.new +//! [window_builder_build]: ./window/struct.WindowBuilder.html#method.build +//! [window_id_fn]: ./window/struct.Window.html#method.id +//! [`Event`]: ./event/enum.Event.html +//! [`WindowEvent`]: ./event/enum.Event.html#variant.WindowEvent +//! [`LoopDestroyed`]: ./event/enum.Event.html#variant.LoopDestroyed +//! [`platform`]: ./platform/index.html #[allow(unused_imports)] #[macro_use] diff --git a/src/monitor.rs b/src/monitor.rs index 4697b1f844..76aaed9e7c 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -1,9 +1,28 @@ +//! Types useful for interacting with a user's monitors. +//! +//! If you want to get basic information about a monitor, you can use the [`MonitorId`][monitor_id] +//! type. This is retreived from an [`AvailableMonitorsIter`][monitor_iter], which can be acquired +//! with: +//! - [`EventLoop::get_available_monitors`][loop_get] +//! - [`Window::get_available_monitors`][window_get]. +//! +//! [monitor_id]: ./struct.MonitorId.html +//! [monitor_iter]: ./struct.AvailableMonitorsIter.html +//! [loop_get]: ../event_loop/struct.EventLoop.html#method.get_available_monitors +//! [window_get]: ../window/struct.Window.html#method.get_available_monitors use std::collections::vec_deque::IntoIter as VecDequeIter; use platform_impl; use dpi::{PhysicalPosition, PhysicalSize}; -/// An iterator for the list of available monitors. +/// An iterator over all available monitors. +/// +/// Can be acquired with: +/// - [`EventLoop::get_available_monitors`][loop_get] +/// - [`Window::get_available_monitors`][window_get]. +/// +/// [loop_get]: ../event_loop/struct.EventLoop.html#method.get_available_monitors +/// [window_get]: ../window/struct.Window.html#method.get_available_monitors // Implementation note: we retrieve the list once, then serve each element by one by one. // This may change in the future. #[derive(Debug)] diff --git a/src/platform/desktop.rs b/src/platform/desktop.rs index 51da320107..2aaa9cf219 100644 --- a/src/platform/desktop.rs +++ b/src/platform/desktop.rs @@ -9,11 +9,13 @@ use event_loop::{EventLoop, ControlFlow}; /// Additional methods on `EventLoop` that are specific to desktop platforms. pub trait EventLoopExtDesktop { + /// A type provided by the user that can be passed through `Event::UserEvent`. type UserEvent; + /// Initializes the `winit` event loop. /// - /// Unlikes `run`, this function *does* return control flow to the caller when `control_flow` - /// is set to `ControlFlow::Exit`. + /// Unlikes `run`, this function accepts non-`'static` closures and returns control flow to the + /// caller when `control_flow` is set to `ControlFlow::Exit`. fn run_return(&mut self, event_handler: F) where F: FnMut(Event, &EventLoop, &mut ControlFlow); } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 27ce048d99..ba494ac6d3 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -1,6 +1,6 @@ //! Contains traits with platform-specific methods in them. //! -//! Contains the follow modules: +//! Contains the follow OS-specific modules: //! //! - `android` //! - `ios` @@ -8,8 +8,12 @@ //! - `unix` //! - `windows` //! -//! However only the module corresponding to the platform you're compiling to will be available. +//! And the following platform-specific module: +//! +//! - `desktop` (available on `windows`, `unix`, and `macos`) //! +//! However only the module corresponding to the platform you're compiling to will be available. + pub mod android; pub mod ios; pub mod macos; diff --git a/src/window.rs b/src/window.rs index 36652072ec..5085c21d6f 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,3 +1,4 @@ +//! The `Window` struct and associated types. use std::{fmt, error}; use platform_impl; @@ -578,6 +579,7 @@ impl Window { MonitorId { inner: self.window.get_primary_monitor() } } + /// Returns an identifier unique to the window. #[inline] pub fn id(&self) -> WindowId { WindowId(self.window.id()) From fba41f7a7ed8585cbb658b6d0b2f34f75482cb3d Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 23 Aug 2018 19:09:53 -0400 Subject: [PATCH 16/40] Small changes to examples --- examples/window.rs | 2 +- examples/{run_return.rs => window_run_return.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename examples/{run_return.rs => window_run_return.rs} (100%) diff --git a/examples/window.rs b/examples/window.rs index ef7c790c63..9f55890d49 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -11,7 +11,7 @@ fn main() { .build(&events_loop) .unwrap(); - events_loop.run(move |event, _, control_flow| { + events_loop.run(|event, _, control_flow| { println!("{:?}", event); match event { diff --git a/examples/run_return.rs b/examples/window_run_return.rs similarity index 100% rename from examples/run_return.rs rename to examples/window_run_return.rs From 0f344087630ae252c9c8f453864e684a1a5405b1 Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 23 Aug 2018 20:13:53 -0400 Subject: [PATCH 17/40] Improve docs for run and run_return --- src/event_loop.rs | 5 +++-- src/platform/desktop.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/event_loop.rs b/src/event_loop.rs index 447738547d..7c7046c9a7 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -105,8 +105,9 @@ impl EventLoop { MonitorId { inner: self.events_loop.get_primary_monitor() } } - /// Hijacks the calling thread and initializes the `winit` event loop. Can take a - /// `FnMut(Event, &EventLoop) -> ControlFlow` or a custom `EventHandler` type. + /// Hijacks the calling thread and initializes the `winit` event loop with the provided + /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to + /// access any data from the calling context. /// /// Any values not passed to this function will *not* be dropped. #[inline] diff --git a/src/platform/desktop.rs b/src/platform/desktop.rs index 2aaa9cf219..8e14346ef3 100644 --- a/src/platform/desktop.rs +++ b/src/platform/desktop.rs @@ -14,8 +14,8 @@ pub trait EventLoopExtDesktop { /// Initializes the `winit` event loop. /// - /// Unlikes `run`, this function accepts non-`'static` closures and returns control flow to the - /// caller when `control_flow` is set to `ControlFlow::Exit`. + /// Unlikes `run`, this function accepts non-`'static` (i.e. non-`move`) closures and returns + /// control flow to the caller when `control_flow` is set to `ControlFlow::Exit`. fn run_return(&mut self, event_handler: F) where F: FnMut(Event, &EventLoop, &mut ControlFlow); } From 8d8d9b7cd1386c99c40023d86e17d10c3fd6652f Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 23 Aug 2018 20:16:52 -0400 Subject: [PATCH 18/40] Change instances of "events_loop" to "event_loop" --- examples/cursor.rs | 6 ++--- examples/cursor_grab.rs | 6 ++--- examples/fullscreen.rs | 10 ++++---- examples/handling_close.rs | 6 ++--- examples/min_max_size.rs | 6 ++--- examples/multiwindow.rs | 8 +++--- examples/proxy.rs | 10 ++++---- examples/request_redraw.rs | 6 ++--- examples/resizable.rs | 6 ++--- examples/timer.rs | 6 ++--- examples/transparent.rs | 6 ++--- examples/window.rs | 6 ++--- examples/window_icon.rs | 6 ++--- examples/window_run_return.rs | 10 ++++---- src/event_loop.rs | 16 ++++++------ src/lib.rs | 12 ++++----- src/platform/android.rs | 2 +- src/platform/desktop.rs | 2 +- src/platform/unix.rs | 10 ++++---- src/platform/windows.rs | 2 +- src/platform_impl/emscripten/mod.rs | 10 ++++---- src/platform_impl/ios/mod.rs | 6 ++--- src/platform_impl/linux/mod.rs | 12 ++++----- src/platform_impl/linux/wayland/event_loop.rs | 25 +++++++++++++++++-- src/platform_impl/linux/wayland/keyboard.rs | 6 ++--- .../macos/{events_loop.rs => event_loop.rs} | 0 src/platform_impl/macos/mod.rs | 10 ++++---- src/platform_impl/macos/view.rs | 2 +- src/platform_impl/macos/window.rs | 2 +- .../windows/{events_loop.rs => event_loop.rs} | 0 src/platform_impl/windows/mod.rs | 4 +-- src/platform_impl/windows/window.rs | 16 ++++++------ src/window.rs | 16 ++++++------ tests/send_objects.rs | 2 +- 34 files changed, 137 insertions(+), 116 deletions(-) rename src/platform_impl/macos/{events_loop.rs => event_loop.rs} (100%) rename src/platform_impl/windows/{events_loop.rs => event_loop.rs} (100%) diff --git a/examples/cursor.rs b/examples/cursor.rs index 31d28aef7f..27c003ac2d 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -5,14 +5,14 @@ use winit::event::{Event, WindowEvent, ElementState, KeyboardInput}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); - let window = WindowBuilder::new().build(&events_loop).unwrap(); + let window = WindowBuilder::new().build(&event_loop).unwrap(); window.set_title("A fantastic window!"); let mut cursor_idx = 0; - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => { println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]); diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index 101cf33fba..741d0d74aa 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -5,14 +5,14 @@ use winit::event::{Event, WindowEvent, ElementState, KeyboardInput}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let window = WindowBuilder::new() .with_title("Super Cursor Grab'n'Hide Simulator 9000") - .build(&events_loop) + .build(&event_loop) .unwrap(); - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; if let Event::WindowEvent { event, .. } = event { match event { diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index eda82b72a5..b71042365b 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -6,11 +6,11 @@ use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInp use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); // enumerating monitors let monitor = { - for (num, monitor) in events_loop.get_available_monitors().enumerate() { + for (num, monitor) in event_loop.get_available_monitors().enumerate() { println!("Monitor #{}: {:?}", num, monitor.get_name()); } @@ -20,7 +20,7 @@ fn main() { let mut num = String::new(); io::stdin().read_line(&mut num).unwrap(); let num = num.trim().parse().ok().expect("Please enter a number"); - let monitor = events_loop.get_available_monitors().nth(num).expect("Please enter a valid ID"); + let monitor = event_loop.get_available_monitors().nth(num).expect("Please enter a valid ID"); println!("Using {:?}", monitor.get_name()); @@ -30,14 +30,14 @@ fn main() { let window = WindowBuilder::new() .with_title("Hello world!") .with_fullscreen(Some(monitor)) - .build(&events_loop) + .build(&event_loop) .unwrap(); let mut is_fullscreen = true; let mut is_maximized = false; let mut decorations = true; - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { println!("{:?}", event); *control_flow = ControlFlow::Wait; diff --git a/examples/handling_close.rs b/examples/handling_close.rs index 8702270bcd..a2db1216b9 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -5,16 +5,16 @@ use winit::event::{Event, WindowEvent, KeyboardInput}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let _window = WindowBuilder::new() .with_title("Your faithful window") - .build(&events_loop) + .build(&event_loop) .unwrap(); let mut close_requested = false; - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { use winit::event::ElementState::Released; use winit::event::VirtualKeyCode::{N, Y}; diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index 4a8a4e25da..dea437635c 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -6,16 +6,16 @@ use winit::event::{Event, WindowEvent}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let window = WindowBuilder::new() - .build(&events_loop) + .build(&event_loop) .unwrap(); window.set_min_dimensions(Some(LogicalSize::new(400.0, 200.0))); window.set_max_dimensions(Some(LogicalSize::new(800.0, 400.0))); - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index b5774b5066..cf2703c2dd 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -6,15 +6,15 @@ use winit::event::{Event, WindowEvent, ElementState, KeyboardInput}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let mut windows = HashMap::new(); for _ in 0..3 { - let window = Window::new(&events_loop).unwrap(); + let window = Window::new(&event_loop).unwrap(); windows.insert(window.id(), window); } - events_loop.run(move |event, events_loop, control_flow| { + event_loop.run(move |event, event_loop, control_flow| { *control_flow = ControlFlow::Wait; match event { Event::WindowEvent { event, window_id } => { @@ -30,7 +30,7 @@ fn main() { } }, WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. } => { - let window = Window::new(&events_loop).unwrap(); + let window = Window::new(&event_loop).unwrap(); windows.insert(window.id(), window); }, _ => () diff --git a/examples/proxy.rs b/examples/proxy.rs index f1106fb891..3e9b2e9dfa 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -4,18 +4,18 @@ use winit::event::{Event, WindowEvent}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop: EventLoop = EventLoop::new_user_event(); + let event_loop: EventLoop = EventLoop::new_user_event(); let _window = WindowBuilder::new() .with_title("A fantastic window!") - .build(&events_loop) + .build(&event_loop) .unwrap(); - let proxy = events_loop.create_proxy(); + let proxy = event_loop.create_proxy(); std::thread::spawn(move || { let mut counter = 0; - // Wake up the `events_loop` once every second. + // Wake up the `event_loop` once every second. loop { std::thread::sleep(std::time::Duration::from_secs(1)); proxy.send_event(counter).unwrap(); @@ -23,7 +23,7 @@ fn main() { } }); - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => diff --git a/examples/request_redraw.rs b/examples/request_redraw.rs index 2943953b39..4ed4e8fbae 100644 --- a/examples/request_redraw.rs +++ b/examples/request_redraw.rs @@ -6,14 +6,14 @@ use winit::event::{Event, WindowEvent}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let window = WindowBuilder::new() .with_title("A fantastic window!") - .build(&events_loop) + .build(&event_loop) .unwrap(); - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { diff --git a/examples/resizable.rs b/examples/resizable.rs index b9df0a5f02..f5690b86b7 100644 --- a/examples/resizable.rs +++ b/examples/resizable.rs @@ -4,7 +4,7 @@ use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInp use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let mut resizable = false; @@ -12,10 +12,10 @@ fn main() { .with_title("Hit space to toggle resizability.") .with_dimensions((400, 200).into()) .with_resizable(resizable) - .build(&events_loop) + .build(&event_loop) .unwrap(); - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; match event { Event::WindowEvent { event, .. } => match event { diff --git a/examples/timer.rs b/examples/timer.rs index fb28a73b80..3692d3277e 100644 --- a/examples/timer.rs +++ b/examples/timer.rs @@ -5,14 +5,14 @@ use winit::event::{Event, WindowEvent, StartCause}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let _window = WindowBuilder::new() .with_title("A fantastic window!") - .build(&events_loop) + .build(&event_loop) .unwrap(); - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { diff --git a/examples/transparent.rs b/examples/transparent.rs index 593f2865da..4da6f9f2dd 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -4,15 +4,15 @@ use winit::event::{Event, WindowEvent}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let window = WindowBuilder::new().with_decorations(false) .with_transparency(true) - .build(&events_loop).unwrap(); + .build(&event_loop).unwrap(); window.set_title("A fantastic window!"); - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { println!("{:?}", event); match event { diff --git a/examples/window.rs b/examples/window.rs index 9f55890d49..3d5c7cf7db 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -4,14 +4,14 @@ use winit::event::{Event, WindowEvent}; use winit::event_loop::{EventLoop, ControlFlow}; fn main() { - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let _window = WindowBuilder::new() .with_title("A fantastic window!") - .build(&events_loop) + .build(&event_loop) .unwrap(); - events_loop.run(|event, _, control_flow| { + event_loop.run(|event, _, control_flow| { println!("{:?}", event); match event { diff --git a/examples/window_icon.rs b/examples/window_icon.rs index 545b44c9f6..6991e81f00 100644 --- a/examples/window_icon.rs +++ b/examples/window_icon.rs @@ -23,17 +23,17 @@ fn main() { // feature enabled). let icon = Icon::from_path(path).expect("Failed to open icon"); - let events_loop = EventLoop::new(); + let event_loop = EventLoop::new(); let window = WindowBuilder::new() .with_title("An iconic window!") // At present, this only does anything on Windows and X11, so if you want to save load // time, you can put icon loading behind a function that returns `None` on other platforms. .with_window_icon(Some(icon)) - .build(&events_loop) + .build(&event_loop) .unwrap(); - events_loop.run(move |event, _, control_flow| { + event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; if let Event::WindowEvent { event, .. } = event { use winit::event::WindowEvent::*; diff --git a/examples/window_run_return.rs b/examples/window_run_return.rs index d38dcf5c4f..ff619902e6 100644 --- a/examples/window_run_return.rs +++ b/examples/window_run_return.rs @@ -6,15 +6,15 @@ use winit::event_loop::{EventLoop, ControlFlow}; use winit::platform::desktop::EventLoopExtDesktop; fn main() { - let mut events_loop = EventLoop::new(); + let mut event_loop = EventLoop::new(); let window = WindowBuilder::new() .with_title("A fantastic window!") - .build(&events_loop) + .build(&event_loop) .unwrap(); println!("Close the window to continue."); - events_loop.run_return(|event, _, control_flow| { + event_loop.run_return(|event, _, control_flow| { match event { Event::WindowEvent { event: WindowEvent::CloseRequested, @@ -27,11 +27,11 @@ fn main() { let _window_2 = WindowBuilder::new() .with_title("A second, fantasticer window!") - .build(&events_loop) + .build(&event_loop) .unwrap(); println!("Wa ha ha! You thought that closing the window would finish this?!"); - events_loop.run_return(|event, _, control_flow| { + event_loop.run_return(|event, _, control_flow| { match event { Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/src/event_loop.rs b/src/event_loop.rs index 7c7046c9a7..93f123ef41 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -30,7 +30,7 @@ use monitor::{AvailableMonitorsIter, MonitorId}; /// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the /// `EventLoopProxy` allows you to wakeup an `EventLoop` from an other thread. pub struct EventLoop { - pub(crate) events_loop: platform_impl::EventLoop, + pub(crate) event_loop: platform_impl::EventLoop, pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync } @@ -85,7 +85,7 @@ impl EventLoop { /// fallback on x11. If this variable is set with any other value, winit will panic. pub fn new_user_event() -> EventLoop { EventLoop { - events_loop: platform_impl::EventLoop::new(), + event_loop: platform_impl::EventLoop::new(), _marker: ::std::marker::PhantomData, } } @@ -95,14 +95,14 @@ impl EventLoop { // Note: should be replaced with `-> impl Iterator` once stable. #[inline] pub fn get_available_monitors(&self) -> AvailableMonitorsIter { - let data = self.events_loop.get_available_monitors(); + let data = self.event_loop.get_available_monitors(); AvailableMonitorsIter{ data: data.into_iter() } } /// Returns the primary monitor of the system. #[inline] pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId { inner: self.events_loop.get_primary_monitor() } + MonitorId { inner: self.event_loop.get_primary_monitor() } } /// Hijacks the calling thread and initializes the `winit` event loop with the provided @@ -114,14 +114,14 @@ impl EventLoop { pub fn run(self, event_handler: F) -> ! where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow) { - self.events_loop.run(event_handler) + self.event_loop.run(event_handler) } /// Creates an `EventLoopProxy` that can be used to wake up the `EventLoop` from another /// thread. pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { - events_loop_proxy: self.events_loop.create_proxy(), + event_loop_proxy: self.event_loop.create_proxy(), } } } @@ -129,7 +129,7 @@ impl EventLoop { /// Used to send custom events to `EventLoop`. #[derive(Clone)] pub struct EventLoopProxy { - events_loop_proxy: platform_impl::EventLoopProxy, + event_loop_proxy: platform_impl::EventLoopProxy, } impl EventLoopProxy { @@ -139,7 +139,7 @@ impl EventLoopProxy { /// /// Returns an `Err` if the associated `EventLoop` no longer exists. pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { - self.events_loop_proxy.send_event(event) + self.event_loop_proxy.send_event(event) } } diff --git a/src/lib.rs b/src/lib.rs index 69a1db0e66..48972433a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,13 +7,13 @@ //! //! ```no_run //! use winit::event_loop::EventLoop; -//! let events_loop = EventLoop::new(); +//! let event_loop = EventLoop::new(); //! ``` //! //! Once this is done there are two ways to create a [`Window`]: //! -//! - Calling [`Window::new(&events_loop)`][window_new]. -//! - Calling [`let builder = WindowBuilder::new()`][window_builder_new] then [`builder.build(&events_loop)`][window_builder_build]. +//! - Calling [`Window::new(&event_loop)`][window_new]. +//! - Calling [`let builder = WindowBuilder::new()`][window_builder_new] then [`builder.build(&event_loop)`][window_builder_build]. //! //! The first way is the simplest way and will give you default values for everything. //! @@ -28,7 +28,7 @@ //! The events generated by a [`Window`] can be retreived from the [`EventLoop`] the [`Window`] was created //! with. //! -//! You do this by calling [`events_loop.run(...)`][event_loop_run]. This function will run forever +//! You do this by calling [`event_loop.run(...)`][event_loop_run]. This function will run forever //! unless `control_flow` is set to [`ControlFlow`]`::`[`Exit`], at which point [`Event`]`::`[`LoopDestroyed`] //! is emitted and the entire program terminates. //! @@ -36,9 +36,9 @@ //! use winit::event_loop::ControlFlow; //! use winit::event::{Event, WindowEvent}; //! # use winit::event_loop::EventLoop; -//! # let events_loop = EventLoop::new(); +//! # let event_loop = EventLoop::new(); //! -//! events_loop.run(move |event, _, control_flow| { +//! event_loop.run(move |event, _, control_flow| { //! match event { //! Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { //! println!("The close button was pressed; stopping"); diff --git a/src/platform/android.rs b/src/platform/android.rs index 67ce262688..37ee0e1d4b 100644 --- a/src/platform/android.rs +++ b/src/platform/android.rs @@ -13,7 +13,7 @@ pub trait EventLoopExtAndroid { impl EventLoopExtAndroid for EventLoop { fn set_suspend_callback(&self, cb: Option ()>>) { - self.events_loop.set_suspend_callback(cb); + self.event_loop.set_suspend_callback(cb); } } diff --git a/src/platform/desktop.rs b/src/platform/desktop.rs index 8e14346ef3..5f32460b2f 100644 --- a/src/platform/desktop.rs +++ b/src/platform/desktop.rs @@ -26,6 +26,6 @@ impl EventLoopExtDesktop for EventLoop { fn run_return(&mut self, event_handler: F) where F: FnMut(Event, &EventLoop, &mut ControlFlow) { - self.events_loop.run_return(event_handler) + self.event_loop.run_return(event_handler) } } diff --git a/src/platform/unix.rs b/src/platform/unix.rs index 7a0929d8e6..43bc316ca5 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -50,7 +50,7 @@ impl EventLoopExtUnix for EventLoop { fn new_x11() -> Result { LinuxEventLoop::new_x11().map(|ev| EventLoop { - events_loop: ev, + event_loop: ev, _marker: ::std::marker::PhantomData, } ) @@ -59,7 +59,7 @@ impl EventLoopExtUnix for EventLoop { #[inline] fn new_wayland() -> Self { EventLoop { - events_loop: match LinuxEventLoop::new_wayland() { + event_loop: match LinuxEventLoop::new_wayland() { Ok(e) => e, Err(_) => panic!() // TODO: propagate }, @@ -69,18 +69,18 @@ impl EventLoopExtUnix for EventLoop { #[inline] fn is_wayland(&self) -> bool { - self.events_loop.is_wayland() + self.event_loop.is_wayland() } #[inline] fn is_x11(&self) -> bool { - !self.events_loop.is_wayland() + !self.event_loop.is_wayland() } #[inline] #[doc(hidden)] fn get_xlib_xconnection(&self) -> Option> { - self.events_loop.x_connection().cloned() + self.event_loop.x_connection().cloned() } } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 3a4e08bab6..b5fd561ece 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -22,7 +22,7 @@ impl EventLoopExtWindows for EventLoop { #[inline] fn new_dpi_unaware() -> Self { EventLoop { - events_loop: WindowsEventLoop::with_dpi_awareness(false), + event_loop: WindowsEventLoop::with_dpi_awareness(false), _marker: ::std::marker::PhantomData, } } diff --git a/src/platform_impl/emscripten/mod.rs b/src/platform_impl/emscripten/mod.rs index 0fb85a2e54..ca73682690 100644 --- a/src/platform_impl/emscripten/mod.rs +++ b/src/platform_impl/emscripten/mod.rs @@ -366,11 +366,11 @@ fn em_try(res: ffi::EMSCRIPTEN_RESULT) -> Result<(), String> { } impl Window { - pub fn new(events_loop: &EventLoop, attribs: ::WindowAttributes, + pub fn new(event_loop: &EventLoop, attribs: ::WindowAttributes, _pl_attribs: PlatformSpecificWindowBuilderAttributes) -> Result { - if events_loop.window.lock().unwrap().is_some() { + if event_loop.window.lock().unwrap().is_some() { return Err(::CreationError::OsError("Cannot create another window".to_owned())); } @@ -419,7 +419,7 @@ impl Window { window.set_inner_size(size); } - *events_loop.window.lock().unwrap() = Some(window.window.clone()); + *event_loop.window.lock().unwrap() = Some(window.window.clone()); Ok(window) } @@ -613,9 +613,9 @@ impl Window { impl Drop for Window { fn drop(&mut self) { - // Delete window from events_loop + // Delete window from event_loop // TODO: ? - /*if let Some(ev) = self.events_loop.upgrade() { + /*if let Some(ev) = self.event_loop.upgrade() { let _ = ev.window.lock().unwrap().take().unwrap(); }*/ diff --git a/src/platform_impl/ios/mod.rs b/src/platform_impl/ios/mod.rs index afdbcef357..9f37510296 100644 --- a/src/platform_impl/ios/mod.rs +++ b/src/platform_impl/ios/mod.rs @@ -199,7 +199,7 @@ impl MonitorId { } } -pub struct EventsLoop { +pub struct EventLoop { events_queue: Arc>>, } @@ -213,7 +213,7 @@ impl EventLoop { panic!("`EventLoop` can only be created on the main thread on iOS"); } } - EventsLoop { events_queue: Default::default() } + EventLoop { events_queue: Default::default() } } #[inline] @@ -238,7 +238,7 @@ impl EventLoop { unsafe { // jump hack, so we won't quit on willTerminate event before processing it - assert!(JMPBUF.is_some(), "`EventsLoop::poll_events` must be called after window creation on iOS"); + assert!(JMPBUF.is_some(), "`EventLoop::poll_events` must be called after window creation on iOS"); if setjmp(mem::transmute_copy(&mut JMPBUF)) != 0 { if let Some(event) = self.events_queue.borrow_mut().pop_front() { callback(event); diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index dd9d4a1026..c1eea896a5 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -122,16 +122,16 @@ impl MonitorId { impl Window { #[inline] pub fn new( - events_loop: &EventLoop, + event_loop: &EventLoop, attribs: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes, ) -> Result { - match *events_loop { - EventLoop::Wayland(ref events_loop) => { - wayland::Window::new(events_loop, attribs).map(Window::Wayland) + match *event_loop { + EventLoop::Wayland(ref event_loop) => { + wayland::Window::new(event_loop, attribs).map(Window::Wayland) }, - EventLoop::X(ref events_loop) => { - x11::Window::new(events_loop, attribs, pl_attribs).map(Window::X) + EventLoop::X(ref event_loop) => { + x11::Window::new(event_loop, attribs, pl_attribs).map(Window::X) }, } } diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index f19713e968..b54d1d7919 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -131,7 +131,7 @@ impl EventLoop { }, ).unwrap(); - Ok(EventsLoop { + Ok(EventLoop { display, evq: RefCell::new(event_queue), sink, @@ -282,7 +282,7 @@ struct SeatManager { sink: Arc>, store: Arc>, seats: Arc)>>>, - events_loop_proxy: EventsLoopProxy, + event_loop_proxy: EventLoopProxy, } impl SeatManager { @@ -308,12 +308,25 @@ impl SeatManager { modifiers_tracker: Arc::new(Mutex::new(ModifiersState::default())), }; let seat = registry +<<<<<<< HEAD .bind(min(version, 5), id, move |seat| { seat.implement(move |event, seat| { seat_data.receive(event, seat) }, ()) }) .unwrap(); +======= + .bind::(min(version, 5), id) + .unwrap() + .implement(SeatData { + sink: self.sink.clone(), + store: self.store.clone(), + pointer: None, + keyboard: None, + touch: None, + event_loop_proxy: self.event_loop_proxy.clone(), + }); +>>>>>>> Change instances of "events_loop" to "event_loop" self.store.lock().unwrap().new_seat(&seat); self.seats.lock().unwrap().push((id, seat)); } @@ -337,8 +350,12 @@ struct SeatData { pointer: Option>, keyboard: Option>, touch: Option>, +<<<<<<< HEAD events_loop_proxy: EventsLoopProxy, modifiers_tracker: Arc>, +======= + event_loop_proxy: EventLoopProxy, +>>>>>>> Change instances of "events_loop" to "event_loop" } impl SeatData { @@ -369,8 +386,12 @@ impl SeatData { self.keyboard = Some(super::keyboard::init_keyboard( &seat, self.sink.clone(), +<<<<<<< HEAD self.events_loop_proxy.clone(), self.modifiers_tracker.clone(), +======= + self.event_loop_proxy.clone(), +>>>>>>> Change instances of "events_loop" to "event_loop" )) } // destroy keyboard if applicable diff --git a/src/platform_impl/linux/wayland/keyboard.rs b/src/platform_impl/linux/wayland/keyboard.rs index 30b60b1279..d8457d5d74 100644 --- a/src/platform_impl/linux/wayland/keyboard.rs +++ b/src/platform_impl/linux/wayland/keyboard.rs @@ -1,6 +1,6 @@ use std::sync::{Arc, Mutex}; -use super::{make_wid, DeviceId, EventsLoopProxy, EventsLoopSink}; +use super::{make_wid, DeviceId, EventLoopProxy, EventLoopSink}; use sctk::keyboard::{ self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind, }; @@ -14,7 +14,7 @@ use {ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent}; pub fn init_keyboard( seat: &Proxy, sink: Arc>, - events_loop_proxy: EventLoopProxy, + event_loop_proxy: EventLoopProxy, modifiers_tracker: Arc>, ) -> Proxy { // { variables to be captured by the closures @@ -108,7 +108,7 @@ pub fn init_keyboard( guard.send_event(WindowEvent::ReceivedCharacter(chr), wid); } } - events_loop_proxy.wakeup().unwrap(); + event_loop_proxy.wakeup().unwrap(); } }, ); diff --git a/src/platform_impl/macos/events_loop.rs b/src/platform_impl/macos/event_loop.rs similarity index 100% rename from src/platform_impl/macos/events_loop.rs rename to src/platform_impl/macos/event_loop.rs diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index 53d2a785ea..5c9de5d2ad 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -1,6 +1,6 @@ #![cfg(target_os = "macos")] -pub use self::events_loop::{EventLoop, Proxy as EventLoopProxy}; +pub use self::event_loop::{EventLoop, Proxy as EventLoopProxy}; pub use self::monitor::MonitorId; pub use self::window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, Window2}; use std::sync::Arc; @@ -24,20 +24,20 @@ impl ::std::ops::Deref for Window { impl Window { - pub fn new(events_loop: &EventLoop, + pub fn new(event_loop: &EventLoop, attributes: ::WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes) -> Result { - let weak_shared = Arc::downgrade(&events_loop.shared); + let weak_shared = Arc::downgrade(&event_loop.shared); let window = Arc::new(try!(Window2::new(weak_shared, attributes, pl_attribs))); let weak_window = Arc::downgrade(&window); - events_loop.shared.windows.lock().unwrap().push(weak_window); + event_loop.shared.windows.lock().unwrap().push(weak_window); Ok(Window { window: window }) } } -mod events_loop; +mod event_loop; mod ffi; mod monitor; mod util; diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index 6b82726454..c5ebc18c66 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -14,7 +14,7 @@ use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Protocol, Sel, BOOL, YES}; use {ElementState, Event, KeyboardInput, MouseButton, WindowEvent, WindowId}; -use platform_impl::platform::events_loop::{DEVICE_ID, event_mods, Shared, to_virtual_key_code, check_additional_virtual_key_codes}; +use platform_impl::platform::event_loop::{DEVICE_ID, event_mods, Shared, to_virtual_key_code, check_additional_virtual_key_codes}; use platform_impl::platform::util; use platform_impl::platform::ffi::*; use platform_impl::platform::window::{get_window_id, IdRef}; diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index 2ca3187b5f..30a305c44d 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -42,7 +42,7 @@ use { use CreationError::OsError; use os::macos::{ActivationPolicy, WindowExt}; use platform_impl::platform::{ffi, util}; -use platform_impl::platform::events_loop::{EventLoop, Shared}; +use platform_impl::platform::event_loop::{EventLoop, Shared}; use platform_impl::platform::view::{new_view, set_ime_spot}; use window::MonitorId as RootMonitorId; diff --git a/src/platform_impl/windows/events_loop.rs b/src/platform_impl/windows/event_loop.rs similarity index 100% rename from src/platform_impl/windows/events_loop.rs rename to src/platform_impl/windows/event_loop.rs diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 02b18770d5..f6c5ed6294 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -3,7 +3,7 @@ use winapi; use winapi::shared::windef::HWND; -pub use self::events_loop::{EventLoop, EventLoopProxy}; +pub use self::event_loop::{EventLoop, EventLoopProxy}; pub use self::monitor::MonitorId; pub use self::window::Window; @@ -54,7 +54,7 @@ unsafe impl Sync for WindowId {} mod dpi; mod drop_handler; mod event; -mod events_loop; +mod event_loop; mod icon; mod monitor; mod raw_input; diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 37d1f33865..d1e2b0b217 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -23,8 +23,8 @@ use dpi::{LogicalPosition, LogicalSize, PhysicalSize}; use monitor::MonitorId as RootMonitorId; use platform_impl::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, WindowId}; use platform_impl::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi}; -use platform_impl::platform::events_loop::{self, EventLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}; -use platform_impl::platform::events_loop::WindowState; +use platform_impl::platform::event_loop::{self, EventLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}; +use platform_impl::platform::event_loop::WindowState; use platform_impl::platform::icon::{self, IconType, WinIcon}; use platform_impl::platform::monitor; use platform_impl::platform::raw_input::register_all_mice_and_keyboards_for_raw_input; @@ -42,7 +42,7 @@ pub struct Window { window_state: Arc>, // The events loop proxy. - thread_executor: events_loop::EventLoopThreadExecutor, + thread_executor: event_loop::EventLoopThreadExecutor, } // https://blogs.msdn.microsoft.com/oldnewthing/20131017-00/?p=2903 @@ -98,13 +98,13 @@ impl Window { file_drop_handler }; - let subclass_input = events_loop::SubclassInput { + let subclass_input = event_loop::SubclassInput { window_state: win.window_state.clone(), event_loop_runner: event_loop.runner_shared.clone(), file_drop_handler, }; - events_loop::subclass_window(win.window.0, subclass_input); + event_loop::subclass_window(win.window.0, subclass_input); win }) } @@ -517,7 +517,7 @@ impl Window { if window_state.fullscreen.is_none() || window_state.saved_window_info.is_none() { let rect = util::get_window_rect(self.window.0).expect("`GetWindowRect` failed"); let dpi_factor = Some(window_state.dpi_factor); - window_state.saved_window_info = Some(events_loop::SavedWindowInfo { + window_state.saved_window_info = Some(event_loop::SavedWindowInfo { style: winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE), ex_style: winuser::GetWindowLongW(self.window.0, winuser::GWL_EXSTYLE), rect, @@ -852,7 +852,7 @@ pub unsafe fn adjust_size( unsafe fn init( mut attributes: WindowAttributes, mut pl_attribs: PlatformSpecificWindowBuilderAttributes, - event_loop: &events_loop::EventLoop, + event_loop: &event_loop::EventLoop, ) -> Result { let title = OsStr::new(&attributes.title) .encode_wide() @@ -1043,7 +1043,7 @@ unsafe fn init( .map(|logical_size| PhysicalSize::from_logical(logical_size, dpi_factor)); let min_size = attributes.min_dimensions .map(|logical_size| PhysicalSize::from_logical(logical_size, dpi_factor)); - let mut window_state = events_loop::WindowState { + let mut window_state = event_loop::WindowState { max_size, min_size, dpi_factor, diff --git a/src/window.rs b/src/window.rs index 5085c21d6f..bd428809ef 100644 --- a/src/window.rs +++ b/src/window.rs @@ -17,10 +17,10 @@ pub use icon::*; /// use winit::event::{Event, WindowEvent}; /// use winit::event_loop::{EventLoop, ControlFlow}; /// -/// let mut events_loop = EventLoop::new(); -/// let window = Window::new(&events_loop).unwrap(); +/// let mut event_loop = EventLoop::new(); +/// let window = Window::new(&event_loop).unwrap(); /// -/// events_loop.run(move |event, _, control_flow| { +/// event_loop.run(move |event, _, control_flow| { /// match event { /// Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { /// *control_flow = ControlFlow::Exit @@ -283,7 +283,7 @@ impl WindowBuilder { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn build(mut self, events_loop: &EventLoop) -> Result { + pub fn build(mut self, event_loop: &EventLoop) -> Result { self.window.dimensions = Some(self.window.dimensions.unwrap_or_else(|| { if let Some(ref monitor) = self.window.fullscreen { // resizing the window to the dimensions of the monitor when fullscreen @@ -296,7 +296,7 @@ impl WindowBuilder { // building platform_impl::Window::new( - &events_loop.events_loop, + &event_loop.event_loop, self.window, self.platform_specific, ).map(|window| Window { window }) @@ -306,14 +306,14 @@ impl WindowBuilder { impl Window { /// Creates a new Window for platforms where this is appropriate. /// - /// This function is equivalent to `WindowBuilder::new().build(events_loop)`. + /// This function is equivalent to `WindowBuilder::new().build(event_loop)`. /// /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn new(events_loop: &EventLoop) -> Result { + pub fn new(event_loop: &EventLoop) -> Result { let builder = WindowBuilder::new(); - builder.build(events_loop) + builder.build(event_loop) } /// Modifies the title of the window. diff --git a/tests/send_objects.rs b/tests/send_objects.rs index 4e61938c10..c2e890f865 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -3,7 +3,7 @@ extern crate winit; fn needs_send() {} #[test] -fn events_loop_proxy_send() { +fn event_loop_proxy_send() { // ensures that `winit::EventLoopProxy` implements `Send` needs_send::>(); } From deb7d379b7c04e61d6d50ff655eccac0ad692e44 Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 23 Aug 2018 20:19:56 -0400 Subject: [PATCH 19/40] Rename MonitorId to MonitorHandle --- src/dpi.rs | 2 +- src/event_loop.rs | 6 +- src/monitor.rs | 24 ++++--- src/platform/ios.rs | 8 +-- src/platform/macos.rs | 8 +-- src/platform/unix.rs | 8 +-- src/platform/windows.rs | 8 +-- src/platform_impl/android/mod.rs | 40 ++++++------ src/platform_impl/emscripten/mod.rs | 28 ++++----- src/platform_impl/ios/mod.rs | 36 +++++------ src/platform_impl/linux/mod.rs | 62 +++++++++---------- src/platform_impl/linux/wayland/event_loop.rs | 28 ++++----- src/platform_impl/linux/wayland/mod.rs | 2 +- src/platform_impl/linux/wayland/window.rs | 28 ++++----- src/platform_impl/linux/x11/mod.rs | 2 +- src/platform_impl/linux/x11/monitor.rs | 22 +++---- src/platform_impl/linux/x11/window.rs | 20 +++--- src/platform_impl/macos/mod.rs | 2 +- src/platform_impl/macos/monitor.rs | 34 +++++----- src/platform_impl/macos/window.rs | 10 +-- src/platform_impl/windows/event_loop.rs | 4 +- src/platform_impl/windows/mod.rs | 2 +- src/platform_impl/windows/monitor.rs | 32 +++++----- src/platform_impl/windows/window.rs | 10 +-- src/window.rs | 16 ++--- tests/send_objects.rs | 2 +- 26 files changed, 224 insertions(+), 220 deletions(-) diff --git a/src/dpi.rs b/src/dpi.rs index 909c9835dc..cae9b4012c 100644 --- a/src/dpi.rs +++ b/src/dpi.rs @@ -33,7 +33,7 @@ //! windows. This event is sent any time the DPI factor changes, either because the window moved to another monitor, //! or because the user changed the configuration of their screen. //! - You can also retrieve the DPI factor of a monitor by calling -//! [`MonitorId::get_hidpi_factor`](../monitor/struct.MonitorId.html#method.get_hidpi_factor), or the +//! [`MonitorHandle::get_hidpi_factor`](../monitor/struct.MonitorHandle.html#method.get_hidpi_factor), or the //! current DPI factor applied to a window by calling //! [`Window::get_hidpi_factor`](../window/struct.Window.html#method.get_hidpi_factor), which is roughly equivalent //! to `window.get_current_monitor().get_hidpi_factor()`. diff --git a/src/event_loop.rs b/src/event_loop.rs index 93f123ef41..585963ef4c 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -14,7 +14,7 @@ use std::time::Instant; use platform_impl; use event::Event; -use monitor::{AvailableMonitorsIter, MonitorId}; +use monitor::{AvailableMonitorsIter, MonitorHandle}; /// Provides a way to retrieve events from the system and from the windows that were registered to /// the events loop. @@ -101,8 +101,8 @@ impl EventLoop { /// Returns the primary monitor of the system. #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId { inner: self.event_loop.get_primary_monitor() } + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle { inner: self.event_loop.get_primary_monitor() } } /// Hijacks the calling thread and initializes the `winit` event loop with the provided diff --git a/src/monitor.rs b/src/monitor.rs index 76aaed9e7c..7533cb78dd 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -1,12 +1,12 @@ //! Types useful for interacting with a user's monitors. //! -//! If you want to get basic information about a monitor, you can use the [`MonitorId`][monitor_id] +//! If you want to get basic information about a monitor, you can use the [`MonitorHandle`][monitor_id] //! type. This is retreived from an [`AvailableMonitorsIter`][monitor_iter], which can be acquired //! with: //! - [`EventLoop::get_available_monitors`][loop_get] //! - [`Window::get_available_monitors`][window_get]. //! -//! [monitor_id]: ./struct.MonitorId.html +//! [monitor_id]: ./struct.MonitorHandle.html //! [monitor_iter]: ./struct.AvailableMonitorsIter.html //! [loop_get]: ../event_loop/struct.EventLoop.html#method.get_available_monitors //! [window_get]: ../window/struct.Window.html#method.get_available_monitors @@ -27,15 +27,15 @@ use dpi::{PhysicalPosition, PhysicalSize}; // This may change in the future. #[derive(Debug)] pub struct AvailableMonitorsIter { - pub(crate) data: VecDequeIter, + pub(crate) data: VecDequeIter, } impl Iterator for AvailableMonitorsIter { - type Item = MonitorId; + type Item = MonitorHandle; #[inline] - fn next(&mut self) -> Option { - self.data.next().map(|id| MonitorId { inner: id }) + fn next(&mut self) -> Option { + self.data.next().map(|id| MonitorHandle { inner: id }) } #[inline] @@ -44,13 +44,17 @@ impl Iterator for AvailableMonitorsIter { } } -/// Identifier for a monitor. +/// Handle to a monitor. +/// +/// Allows you to retrieve information about a given monitor and can be used in [`Window`] creation. +/// +/// [`Window`]: ../window/struct.Window.html #[derive(Debug, Clone)] -pub struct MonitorId { - pub(crate) inner: platform_impl::MonitorId +pub struct MonitorHandle { + pub(crate) inner: platform_impl::MonitorHandle } -impl MonitorId { +impl MonitorHandle { /// Returns a human-readable name of the monitor. /// /// Returns `None` if the monitor doesn't exist anymore. diff --git a/src/platform/ios.rs b/src/platform/ios.rs index 3e7a3e2a7b..7a2345b044 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -2,7 +2,7 @@ use std::os::raw::c_void; -use {MonitorId, Window, WindowBuilder}; +use {MonitorHandle, Window, WindowBuilder}; /// Additional methods on `Window` that are specific to iOS. pub trait WindowExtIOS { @@ -45,13 +45,13 @@ impl WindowBuilderExtIOS for WindowBuilder { } } -/// Additional methods on `MonitorId` that are specific to iOS. -pub trait MonitorIdExtIOS { +/// Additional methods on `MonitorHandle` that are specific to iOS. +pub trait MonitorHandleExtIOS { /// Returns a pointer to the `UIScreen` that is used by this monitor. fn get_uiscreen(&self) -> *mut c_void; } -impl MonitorIdExtIOS for MonitorId { +impl MonitorHandleExtIOS for MonitorHandle { #[inline] fn get_uiscreen(&self) -> *mut c_void { self.inner.get_uiscreen() as _ diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 24bdc426bd..ef7b10cd46 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -1,7 +1,7 @@ #![cfg(target_os = "macos")] use std::os::raw::c_void; -use {LogicalSize, MonitorId, Window, WindowBuilder}; +use {LogicalSize, MonitorHandle, Window, WindowBuilder}; /// Additional methods on `Window` that are specific to MacOS. pub trait WindowExtMacOS { @@ -137,15 +137,15 @@ impl WindowBuilderExtMacOS for WindowBuilder { } } -/// Additional methods on `MonitorId` that are specific to MacOS. -pub trait MonitorIdExtMacOS { +/// Additional methods on `MonitorHandle` that are specific to MacOS. +pub trait MonitorHandleExtMacOS { /// Returns the identifier of the monitor for Cocoa. fn native_id(&self) -> u32; /// Returns a pointer to the NSScreen representing this monitor. fn get_nsscreen(&self) -> Option<*mut c_void>; } -impl MonitorIdExtMacOS for MonitorId { +impl MonitorHandleExtMacOS for MonitorHandle { #[inline] fn native_id(&self) -> u32 { self.inner.get_native_identifier() diff --git a/src/platform/unix.rs b/src/platform/unix.rs index 43bc316ca5..f611a4f7cc 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use { EventLoop, LogicalSize, - MonitorId, + MonitorHandle, Window, WindowBuilder, }; @@ -279,13 +279,13 @@ impl WindowBuilderExtUnix for WindowBuilder { } } -/// Additional methods on `MonitorId` that are specific to Linux. -pub trait MonitorIdExtUnix { +/// Additional methods on `MonitorHandle` that are specific to Linux. +pub trait MonitorHandleExtUnix { /// Returns the inner identifier of the monitor. fn native_id(&self) -> u32; } -impl MonitorIdExtUnix for MonitorId { +impl MonitorHandleExtUnix for MonitorHandle { #[inline] fn native_id(&self) -> u32 { self.inner.get_native_identifier() diff --git a/src/platform/windows.rs b/src/platform/windows.rs index b5fd561ece..7a9de6880a 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -6,7 +6,7 @@ use libc; use winapi::shared::windef::HWND; use event::DeviceId; -use monitor::MonitorId; +use monitor::MonitorHandle; use event_loop::EventLoop; use window::{Icon, Window, WindowBuilder}; use platform_impl::EventLoop as WindowsEventLoop; @@ -83,8 +83,8 @@ impl WindowBuilderExtWindows for WindowBuilder { } } -/// Additional methods on `MonitorId` that are specific to Windows. -pub trait MonitorIdExtWindows { +/// Additional methods on `MonitorHandle` that are specific to Windows. +pub trait MonitorHandleExtWindows { /// Returns the name of the monitor adapter specific to the Win32 API. fn native_id(&self) -> String; @@ -92,7 +92,7 @@ pub trait MonitorIdExtWindows { fn hmonitor(&self) -> *mut c_void; } -impl MonitorIdExtWindows for MonitorId { +impl MonitorHandleExtWindows for MonitorHandle { #[inline] fn native_id(&self) -> String { self.inner.get_native_identifier() diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 47a8d2ac20..c5a1239e1d 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -24,7 +24,7 @@ use { }; use CreationError::OsError; use events::{Touch, TouchPhase}; -use window::MonitorId as RootMonitorId; +use window::MonitorHandle as RootMonitorHandle; pub struct EventLoop { event_rx: Receiver, @@ -45,15 +45,15 @@ impl EventLoop { } #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { let mut rb = VecDeque::with_capacity(1); - rb.push_back(MonitorId); + rb.push_back(MonitorHandle); rb } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle } pub fn poll_events(&mut self, mut callback: F) @@ -62,7 +62,7 @@ impl EventLoop { while let Ok(event) = self.event_rx.try_recv() { let e = match event{ android_glue::Event::EventMotion(motion) => { - let dpi_factor = MonitorId.get_hidpi_factor(); + let dpi_factor = MonitorHandle.get_hidpi_factor(); let location = LogicalPosition::from_physical( (motion.x as f64, motion.y as f64), dpi_factor, @@ -103,8 +103,8 @@ impl EventLoop { if native_window.is_null() { None } else { - let dpi_factor = MonitorId.get_hidpi_factor(); - let physical_size = MonitorId.get_dimensions(); + let dpi_factor = MonitorHandle.get_hidpi_factor(); + let physical_size = MonitorHandle.get_dimensions(); let size = LogicalSize::from_physical(physical_size, dpi_factor); Some(Event::WindowEvent { window_id: RootWindowId(WindowId), @@ -178,19 +178,19 @@ pub struct Window { } #[derive(Clone)] -pub struct MonitorId; +pub struct MonitorHandle; -impl fmt::Debug for MonitorId { +impl fmt::Debug for MonitorHandle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[derive(Debug)] - struct MonitorId { + struct MonitorHandle { name: Option, dimensions: PhysicalSize, position: PhysicalPosition, hidpi_factor: f64, } - let monitor_id_proxy = MonitorId { + let monitor_id_proxy = MonitorHandle { name: self.get_name(), dimensions: self.get_dimensions(), position: self.get_position(), @@ -201,7 +201,7 @@ impl fmt::Debug for MonitorId { } } -impl MonitorId { +impl MonitorHandle { #[inline] pub fn get_name(&self) -> Option { Some("Primary".to_string()) @@ -357,7 +357,7 @@ impl Window { } #[inline] - pub fn set_fullscreen(&self, _monitor: Option) { + pub fn set_fullscreen(&self, _monitor: Option) { // N/A // Android has single screen maximized apps so nothing to do } @@ -383,20 +383,20 @@ impl Window { } #[inline] - pub fn get_current_monitor(&self) -> RootMonitorId { - RootMonitorId { inner: MonitorId } + pub fn get_current_monitor(&self) -> RootMonitorHandle { + RootMonitorHandle { inner: MonitorHandle } } #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { let mut rb = VecDeque::with_capacity(1); - rb.push_back(MonitorId); + rb.push_back(MonitorHandle); rb } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle } #[inline] diff --git a/src/platform_impl/emscripten/mod.rs b/src/platform_impl/emscripten/mod.rs index ca73682690..c46b163ea4 100644 --- a/src/platform_impl/emscripten/mod.rs +++ b/src/platform_impl/emscripten/mod.rs @@ -10,7 +10,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Mutex, Arc}; use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; -use window::MonitorId as RootMonitorId; +use window::MonitorHandle as RootMonitorHandle; const DOCUMENT_NAME: &'static str = "#document\0"; @@ -31,9 +31,9 @@ pub struct DeviceId; pub struct PlatformSpecificHeadlessBuilderAttributes; #[derive(Debug, Clone)] -pub struct MonitorId; +pub struct MonitorHandle; -impl MonitorId { +impl MonitorHandle { #[inline] pub fn get_name(&self) -> Option { Some("Canvas".to_owned()) @@ -107,15 +107,15 @@ impl EventLoop { } #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { let mut list = VecDeque::with_capacity(1); - list.push_back(MonitorId); + list.push_back(MonitorHandle); list } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle } pub fn poll_events(&self, mut callback: F) @@ -569,7 +569,7 @@ impl Window { } #[inline] - pub fn set_fullscreen(&self, _monitor: Option<::MonitorId>) { + pub fn set_fullscreen(&self, _monitor: Option<::MonitorHandle>) { // iOS has single screen maximized apps so nothing to do } @@ -594,20 +594,20 @@ impl Window { } #[inline] - pub fn get_current_monitor(&self) -> RootMonitorId { - RootMonitorId { inner: MonitorId } + pub fn get_current_monitor(&self) -> RootMonitorHandle { + RootMonitorHandle { inner: MonitorHandle } } #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { let mut list = VecDeque::with_capacity(1); - list.push_back(MonitorId); + list.push_back(MonitorHandle); list } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle } } diff --git a/src/platform_impl/ios/mod.rs b/src/platform_impl/ios/mod.rs index 9f37510296..c7c6ab9bde 100644 --- a/src/platform_impl/ios/mod.rs +++ b/src/platform_impl/ios/mod.rs @@ -82,7 +82,7 @@ use { WindowId as RootEventId, }; use events::{Touch, TouchPhase}; -use window::MonitorId as RootMonitorId; +use window::MonitorHandle as RootMonitorHandle; mod ffi; use self::ffi::{ @@ -145,19 +145,19 @@ impl Drop for DelegateState { } #[derive(Clone)] -pub struct MonitorId; +pub struct MonitorHandle; -impl fmt::Debug for MonitorId { +impl fmt::Debug for MonitorHandle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[derive(Debug)] - struct MonitorId { + struct MonitorHandle { name: Option, dimensions: PhysicalSize, position: PhysicalPosition, hidpi_factor: f64, } - let monitor_id_proxy = MonitorId { + let monitor_id_proxy = MonitorHandle { name: self.get_name(), dimensions: self.get_dimensions(), position: self.get_position(), @@ -168,7 +168,7 @@ impl fmt::Debug for MonitorId { } } -impl MonitorId { +impl MonitorHandle { #[inline] pub fn get_uiscreen(&self) -> id { let class = class!(UIScreen); @@ -217,15 +217,15 @@ impl EventLoop { } #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { let mut rb = VecDeque::with_capacity(1); - rb.push_back(MonitorId); + rb.push_back(MonitorHandle); rb } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle } pub fn poll_events(&mut self, mut callback: F) @@ -330,7 +330,7 @@ impl Window { (&mut *delegate).set_ivar("eventsQueue", mem::transmute::<_, *mut c_void>(events_queue)); // easiest? way to get access to PlatformSpecificWindowBuilderAttributes to configure the view - let rect: CGRect = msg_send![MonitorId.get_uiscreen(), bounds]; + let rect: CGRect = msg_send![MonitorHandle.get_uiscreen(), bounds]; let uiview_class = class!(UIView); let root_view_class = pl_attributes.root_view_class; @@ -462,7 +462,7 @@ impl Window { } #[inline] - pub fn set_fullscreen(&self, _monitor: Option) { + pub fn set_fullscreen(&self, _monitor: Option) { // N/A // iOS has single screen maximized apps so nothing to do } @@ -488,20 +488,20 @@ impl Window { } #[inline] - pub fn get_current_monitor(&self) -> RootMonitorId { - RootMonitorId { inner: MonitorId } + pub fn get_current_monitor(&self) -> RootMonitorHandle { + RootMonitorHandle { inner: MonitorHandle } } #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { let mut rb = VecDeque::with_capacity(1); - rb.push_back(MonitorId); + rb.push_back(MonitorHandle); rb } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle } #[inline] diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index c1eea896a5..b87de6e86a 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -18,7 +18,7 @@ use { WindowAttributes, }; use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; -use window::MonitorId as RootMonitorId; +use window::MonitorHandle as RootMonitorHandle; use self::x11::{XConnection, XError}; use self::x11::ffi::XVisualInfo; pub use self::x11::XNotSupported; @@ -72,49 +72,49 @@ pub enum DeviceId { } #[derive(Debug, Clone)] -pub enum MonitorId { - X(x11::MonitorId), - Wayland(wayland::MonitorId), +pub enum MonitorHandle { + X(x11::MonitorHandle), + Wayland(wayland::MonitorHandle), } -impl MonitorId { +impl MonitorHandle { #[inline] pub fn get_name(&self) -> Option { match self { - &MonitorId::X(ref m) => m.get_name(), - &MonitorId::Wayland(ref m) => m.get_name(), + &MonitorHandle::X(ref m) => m.get_name(), + &MonitorHandle::Wayland(ref m) => m.get_name(), } } #[inline] pub fn get_native_identifier(&self) -> u32 { match self { - &MonitorId::X(ref m) => m.get_native_identifier(), - &MonitorId::Wayland(ref m) => m.get_native_identifier(), + &MonitorHandle::X(ref m) => m.get_native_identifier(), + &MonitorHandle::Wayland(ref m) => m.get_native_identifier(), } } #[inline] pub fn get_dimensions(&self) -> PhysicalSize { match self { - &MonitorId::X(ref m) => m.get_dimensions(), - &MonitorId::Wayland(ref m) => m.get_dimensions(), + &MonitorHandle::X(ref m) => m.get_dimensions(), + &MonitorHandle::Wayland(ref m) => m.get_dimensions(), } } #[inline] pub fn get_position(&self) -> PhysicalPosition { match self { - &MonitorId::X(ref m) => m.get_position(), - &MonitorId::Wayland(ref m) => m.get_position(), + &MonitorHandle::X(ref m) => m.get_position(), + &MonitorHandle::Wayland(ref m) => m.get_position(), } } #[inline] pub fn get_hidpi_factor(&self) -> f64 { match self { - &MonitorId::X(ref m) => m.get_hidpi_factor(), - &MonitorId::Wayland(ref m) => m.get_hidpi_factor() as f64, + &MonitorHandle::X(ref m) => m.get_hidpi_factor(), + &MonitorHandle::Wayland(ref m) => m.get_hidpi_factor() as f64, } } } @@ -289,7 +289,7 @@ impl Window { } #[inline] - pub fn set_fullscreen(&self, monitor: Option) { + pub fn set_fullscreen(&self, monitor: Option) { match self { &Window::X(ref w) => w.set_fullscreen(monitor), &Window::Wayland(ref w) => w.set_fullscreen(monitor) @@ -329,32 +329,32 @@ impl Window { } #[inline] - pub fn get_current_monitor(&self) -> RootMonitorId { + pub fn get_current_monitor(&self) -> RootMonitorHandle { match self { - &Window::X(ref window) => RootMonitorId { inner: MonitorId::X(window.get_current_monitor()) }, - &Window::Wayland(ref window) => RootMonitorId { inner: MonitorId::Wayland(window.get_current_monitor()) }, + &Window::X(ref window) => RootMonitorHandle { inner: MonitorHandle::X(window.get_current_monitor()) }, + &Window::Wayland(ref window) => RootMonitorHandle { inner: MonitorHandle::Wayland(window.get_current_monitor()) }, } } #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { match self { &Window::X(ref window) => window.get_available_monitors() .into_iter() - .map(MonitorId::X) + .map(MonitorHandle::X) .collect(), &Window::Wayland(ref window) => window.get_available_monitors() .into_iter() - .map(MonitorId::Wayland) + .map(MonitorHandle::Wayland) .collect(), } } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { + pub fn get_primary_monitor(&self) -> MonitorHandle { match self { - &Window::X(ref window) => MonitorId::X(window.get_primary_monitor()), - &Window::Wayland(ref window) => MonitorId::Wayland(window.get_primary_monitor()), + &Window::X(ref window) => MonitorHandle::X(window.get_primary_monitor()), + &Window::Wayland(ref window) => MonitorHandle::Wayland(window.get_primary_monitor()), } } } @@ -453,27 +453,27 @@ impl EventLoop { } #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { match *self { EventLoop::Wayland(ref evlp) => evlp .get_available_monitors() .into_iter() - .map(MonitorId::Wayland) + .map(MonitorHandle::Wayland) .collect(), EventLoop::X(ref evlp) => evlp .x_connection() .get_available_monitors() .into_iter() - .map(MonitorId::X) + .map(MonitorHandle::X) .collect(), } } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { + pub fn get_primary_monitor(&self) -> MonitorHandle { match *self { - EventLoop::Wayland(ref evlp) => MonitorId::Wayland(evlp.get_primary_monitor()), - EventLoop::X(ref evlp) => MonitorId::X(evlp.x_connection().get_primary_monitor()), + EventLoop::Wayland(ref evlp) => MonitorHandle::Wayland(evlp.get_primary_monitor()), + EventLoop::X(ref evlp) => MonitorHandle::X(evlp.x_connection().get_primary_monitor()), } } diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index b54d1d7919..eaa39fad64 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -211,11 +211,11 @@ impl EventLoop { } } - pub fn get_primary_monitor(&self) -> MonitorId { + pub fn get_primary_monitor(&self) -> MonitorHandle { get_primary_monitor(&self.env.outputs) } - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { get_available_monitors(&self.env.outputs) } } @@ -452,24 +452,24 @@ impl Drop for SeatData { * Monitor stuff */ -pub struct MonitorId { +pub struct MonitorHandle { pub(crate) proxy: Proxy, pub(crate) mgr: OutputMgr, } -impl Clone for MonitorId { - fn clone(&self) -> MonitorId { - MonitorId { +impl Clone for MonitorHandle { + fn clone(&self) -> MonitorHandle { + MonitorHandle { proxy: self.proxy.clone(), mgr: self.mgr.clone(), } } } -impl fmt::Debug for MonitorId { +impl fmt::Debug for MonitorHandle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[derive(Debug)] - struct MonitorId { + struct MonitorHandle { name: Option, native_identifier: u32, dimensions: PhysicalSize, @@ -477,7 +477,7 @@ impl fmt::Debug for MonitorId { hidpi_factor: i32, } - let monitor_id_proxy = MonitorId { + let monitor_id_proxy = MonitorHandle { name: self.get_name(), native_identifier: self.get_native_identifier(), dimensions: self.get_dimensions(), @@ -489,7 +489,7 @@ impl fmt::Debug for MonitorId { } } -impl MonitorId { +impl MonitorHandle { pub fn get_name(&self) -> Option { self.mgr.with_info(&self.proxy, |_, info| { format!("{} ({})", info.model, info.make) @@ -528,10 +528,10 @@ impl MonitorId { } } -pub fn get_primary_monitor(outputs: &OutputMgr) -> MonitorId { +pub fn get_primary_monitor(outputs: &OutputMgr) -> MonitorHandle { outputs.with_all(|list| { if let Some(&(_, ref proxy, _)) = list.first() { - MonitorId { + MonitorHandle { proxy: proxy.clone(), mgr: outputs.clone(), } @@ -541,10 +541,10 @@ pub fn get_primary_monitor(outputs: &OutputMgr) -> MonitorId { }) } -pub fn get_available_monitors(outputs: &OutputMgr) -> VecDeque { +pub fn get_available_monitors(outputs: &OutputMgr) -> VecDeque { outputs.with_all(|list| { list.iter() - .map(|&(_, ref proxy, _)| MonitorId { + .map(|&(_, ref proxy, _)| MonitorHandle { proxy: proxy.clone(), mgr: outputs.clone(), }) diff --git a/src/platform_impl/linux/wayland/mod.rs b/src/platform_impl/linux/wayland/mod.rs index aa3562f8c6..065dabcc15 100644 --- a/src/platform_impl/linux/wayland/mod.rs +++ b/src/platform_impl/linux/wayland/mod.rs @@ -2,7 +2,7 @@ target_os = "netbsd", target_os = "openbsd"))] pub use self::window::Window; -pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopSink, MonitorId}; +pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopSink, MonitorHandle}; use sctk::reexports::client::protocol::wl_surface; use sctk::reexports::client::Proxy; diff --git a/src/platform_impl/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs index b0f28359b9..dffd926225 100644 --- a/src/platform_impl/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -3,8 +3,8 @@ use std::sync::{Arc, Mutex, Weak}; use {CreationError, MouseCursor, WindowAttributes}; use dpi::{LogicalPosition, LogicalSize}; -use platform_impl::MonitorId as PlatformMonitorId; -use window::MonitorId as RootMonitorId; +use platform_impl::MonitorHandle as PlatformMonitorHandle; +use window::MonitorHandle as RootMonitorHandle; use sctk::window::{ConceptFrame, Event as WEvent, Window as SWindow}; use sctk::reexports::client::{Display, Proxy}; @@ -13,7 +13,7 @@ use sctk::reexports::client::protocol::wl_compositor::RequestsTrait as Composito use sctk::reexports::client::protocol::wl_surface::RequestsTrait as SurfaceRequests; use sctk::output::OutputMgr; -use super::{make_wid, EventLoop, MonitorId, WindowId}; +use super::{make_wid, EventLoop, MonitorHandle, WindowId}; use platform_impl::platform::wayland::event_loop::{get_available_monitors, get_primary_monitor}; pub struct Window { @@ -42,7 +42,7 @@ impl Window { let window_store = evlp.store.clone(); surface.implement(move |event, surface| match event { wl_surface::Event::Enter { output } => { - let dpi_change = list.lock().unwrap().add_output(MonitorId { + let dpi_change = list.lock().unwrap().add_output(MonitorHandle { proxy: output, mgr: omgr.clone(), }); @@ -111,8 +111,8 @@ impl Window { } // Check for fullscreen requirements - if let Some(RootMonitorId { - inner: PlatformMonitorId::Wayland(ref monitor_id), + if let Some(RootMonitorHandle { + inner: PlatformMonitorHandle::Wayland(ref monitor_id), }) = attributes.fullscreen { frame.set_fullscreen(Some(&monitor_id.proxy)); @@ -247,9 +247,9 @@ impl Window { } } - pub fn set_fullscreen(&self, monitor: Option) { - if let Some(RootMonitorId { - inner: PlatformMonitorId::Wayland(ref monitor_id), + pub fn set_fullscreen(&self, monitor: Option) { + if let Some(RootMonitorHandle { + inner: PlatformMonitorHandle::Wayland(ref monitor_id), }) = monitor { self.frame @@ -289,18 +289,18 @@ impl Window { &self.surface } - pub fn get_current_monitor(&self) -> MonitorId { + pub fn get_current_monitor(&self) -> MonitorHandle { // we don't know how much each monitor sees us so... // just return the most recent one ? let guard = self.monitors.lock().unwrap(); guard.monitors.last().unwrap().clone() } - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { get_available_monitors(&self.outputs) } - pub fn get_primary_monitor(&self) -> MonitorId { + pub fn get_primary_monitor(&self) -> MonitorHandle { get_primary_monitor(&self.outputs) } } @@ -412,7 +412,7 @@ impl WindowStore { */ struct MonitorList { - monitors: Vec + monitors: Vec } impl MonitorList { @@ -431,7 +431,7 @@ impl MonitorList { factor } - fn add_output(&mut self, monitor: MonitorId) -> Option { + fn add_output(&mut self, monitor: MonitorHandle) -> Option { let old_dpi = self.compute_hidpi_factor(); let monitor_dpi = monitor.get_hidpi_factor(); self.monitors.push(monitor); diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index e87439e2f2..d97bb8a07b 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -9,7 +9,7 @@ mod dnd; mod ime; pub mod util; -pub use self::monitor::MonitorId; +pub use self::monitor::MonitorHandle; pub use self::window::UnownedWindow; pub use self::xdisplay::{XConnection, XNotSupported, XError}; diff --git a/src/platform_impl/linux/x11/monitor.rs b/src/platform_impl/linux/x11/monitor.rs index 5912d77247..eb313d3270 100644 --- a/src/platform_impl/linux/x11/monitor.rs +++ b/src/platform_impl/linux/x11/monitor.rs @@ -20,7 +20,7 @@ const DISABLE_MONITOR_LIST_CACHING: bool = false; lazy_static! { static ref XRANDR_VERSION: Mutex> = Mutex::default(); - static ref MONITORS: Mutex>> = Mutex::default(); + static ref MONITORS: Mutex>> = Mutex::default(); } fn version_is_at_least(major: c_int, minor: c_int) -> bool { @@ -35,13 +35,13 @@ fn version_is_at_least(major: c_int, minor: c_int) -> bool { } } -pub fn invalidate_cached_monitor_list() -> Option> { +pub fn invalidate_cached_monitor_list() -> Option> { // We update this lazily. (*MONITORS.lock()).take() } #[derive(Debug, Clone)] -pub struct MonitorId { +pub struct MonitorHandle { /// The actual id id: u32, /// The name of the monitor @@ -58,7 +58,7 @@ pub struct MonitorId { pub(crate) rect: util::AaRect, } -impl MonitorId { +impl MonitorHandle { fn from_repr( xconn: &XConnection, resources: *mut XRRScreenResources, @@ -69,7 +69,7 @@ impl MonitorId { let (name, hidpi_factor) = unsafe { xconn.get_output_info(resources, &repr) }; let (dimensions, position) = unsafe { (repr.get_dimensions(), repr.get_position()) }; let rect = util::AaRect::new(position, dimensions); - MonitorId { + MonitorHandle { id, name, hidpi_factor, @@ -104,7 +104,7 @@ impl MonitorId { } impl XConnection { - pub fn get_monitor_for_window(&self, window_rect: Option) -> MonitorId { + pub fn get_monitor_for_window(&self, window_rect: Option) -> MonitorHandle { let monitors = self.get_available_monitors(); let default = monitors .get(0) @@ -128,7 +128,7 @@ impl XConnection { matched_monitor.to_owned() } - fn query_monitor_list(&self) -> Vec { + fn query_monitor_list(&self) -> Vec { unsafe { let root = (self.xlib.XDefaultRootWindow)(self.display); // WARNING: this function is supposedly very slow, on the order of hundreds of ms. @@ -153,7 +153,7 @@ impl XConnection { let monitor = monitors.offset(monitor_index as isize); let is_primary = (*monitor).primary != 0; has_primary |= is_primary; - available.push(MonitorId::from_repr( + available.push(MonitorHandle::from_repr( self, resources, monitor_index as u32, @@ -176,7 +176,7 @@ impl XConnection { let crtc = util::MonitorRepr::from(crtc); let is_primary = crtc.get_output() == primary; has_primary |= is_primary; - available.push(MonitorId::from_repr( + available.push(MonitorHandle::from_repr( self, resources, crtc_id as u32, @@ -201,7 +201,7 @@ impl XConnection { } } - pub fn get_available_monitors(&self) -> Vec { + pub fn get_available_monitors(&self) -> Vec { let mut monitors_lock = MONITORS.lock(); (*monitors_lock) .as_ref() @@ -217,7 +217,7 @@ impl XConnection { } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { + pub fn get_primary_monitor(&self) -> MonitorHandle { self.get_available_monitors() .into_iter() .find(|monitor| monitor.primary) diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index f37a55743e..890f142b08 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -10,10 +10,10 @@ use parking_lot::Mutex; use {Icon, MouseCursor, WindowAttributes}; use CreationError::{self, OsError}; use dpi::{LogicalPosition, LogicalSize}; -use platform_impl::MonitorId as PlatformMonitorId; +use platform_impl::MonitorHandle as PlatformMonitorHandle; use platform_impl::PlatformSpecificWindowBuilderAttributes; -use platform_impl::x11::MonitorId as X11MonitorId; -use window::MonitorId as RootMonitorId; +use platform_impl::x11::MonitorHandle as X11MonitorHandle; +use window::MonitorHandle as RootMonitorHandle; use super::{ffi, util, ImeSender, XConnection, XError, WindowId, EventLoop}; @@ -35,7 +35,7 @@ pub struct SharedState { pub inner_position: Option<(i32, i32)>, pub inner_position_rel_parent: Option<(i32, i32)>, pub guessed_dpi: Option, - pub last_monitor: Option, + pub last_monitor: Option, pub dpi_adjusted: Option<(f64, f64)>, // Used to restore position after exiting fullscreen. pub restore_position: Option<(i32, i32)>, @@ -511,7 +511,7 @@ impl UnownedWindow { self.set_netwm(fullscreen.into(), (fullscreen_atom as c_long, 0, 0, 0)) } - fn set_fullscreen_inner(&self, monitor: Option) -> util::Flusher { + fn set_fullscreen_inner(&self, monitor: Option) -> util::Flusher { match monitor { None => { let flusher = self.set_fullscreen_hint(false); @@ -520,7 +520,7 @@ impl UnownedWindow { } flusher }, - Some(RootMonitorId { inner: PlatformMonitorId::X(monitor) }) => { + Some(RootMonitorHandle { inner: PlatformMonitorHandle::X(monitor) }) => { let window_position = self.get_position_physical(); self.shared_state.lock().restore_position = window_position; let monitor_origin: (i32, i32) = monitor.get_position().into(); @@ -532,7 +532,7 @@ impl UnownedWindow { } #[inline] - pub fn set_fullscreen(&self, monitor: Option) { + pub fn set_fullscreen(&self, monitor: Option) { self.set_fullscreen_inner(monitor) .flush() .expect("Failed to change window fullscreen state"); @@ -549,7 +549,7 @@ impl UnownedWindow { } #[inline] - pub fn get_current_monitor(&self) -> X11MonitorId { + pub fn get_current_monitor(&self) -> X11MonitorHandle { let monitor = self.shared_state .lock() .last_monitor @@ -563,11 +563,11 @@ impl UnownedWindow { }) } - pub fn get_available_monitors(&self) -> Vec { + pub fn get_available_monitors(&self) -> Vec { self.xconn.get_available_monitors() } - pub fn get_primary_monitor(&self) -> X11MonitorId { + pub fn get_primary_monitor(&self) -> X11MonitorHandle { self.xconn.get_primary_monitor() } diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index 5c9de5d2ad..e97d18903c 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -1,7 +1,7 @@ #![cfg(target_os = "macos")] pub use self::event_loop::{EventLoop, Proxy as EventLoopProxy}; -pub use self::monitor::MonitorId; +pub use self::monitor::MonitorHandle; pub use self::window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, Window2}; use std::sync::Arc; diff --git a/src/platform_impl/macos/monitor.rs b/src/platform_impl/macos/monitor.rs index 062cf73c3f..7b3e848832 100644 --- a/src/platform_impl/macos/monitor.rs +++ b/src/platform_impl/macos/monitor.rs @@ -11,13 +11,13 @@ use super::EventLoop; use super::window::{IdRef, Window2}; #[derive(Clone, PartialEq)] -pub struct MonitorId(CGDirectDisplayID); +pub struct MonitorHandle(CGDirectDisplayID); -fn get_available_monitors() -> VecDeque { +fn get_available_monitors() -> VecDeque { if let Ok(displays) = CGDisplay::active_displays() { let mut monitors = VecDeque::with_capacity(displays.len()); for d in displays { - monitors.push_back(MonitorId(d)); + monitors.push_back(MonitorHandle(d)); } monitors } else { @@ -25,44 +25,44 @@ fn get_available_monitors() -> VecDeque { } } -pub fn get_primary_monitor() -> MonitorId { - let id = MonitorId(CGDisplay::main().id); +pub fn get_primary_monitor() -> MonitorHandle { + let id = MonitorHandle(CGDisplay::main().id); id } impl EventLoop { #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { get_available_monitors() } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { + pub fn get_primary_monitor(&self) -> MonitorHandle { get_primary_monitor() } - pub fn make_monitor_from_display(id: CGDirectDisplayID) -> MonitorId { - let id = MonitorId(id); + pub fn make_monitor_from_display(id: CGDirectDisplayID) -> MonitorHandle { + let id = MonitorHandle(id); id } } impl Window2 { #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { get_available_monitors() } #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { + pub fn get_primary_monitor(&self) -> MonitorHandle { get_primary_monitor() } } -impl fmt::Debug for MonitorId { +impl fmt::Debug for MonitorHandle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[derive(Debug)] - struct MonitorId { + struct MonitorHandle { name: Option, native_identifier: u32, dimensions: PhysicalSize, @@ -70,7 +70,7 @@ impl fmt::Debug for MonitorId { hidpi_factor: f64, } - let monitor_id_proxy = MonitorId { + let monitor_id_proxy = MonitorHandle { name: self.get_name(), native_identifier: self.get_native_identifier(), dimensions: self.get_dimensions(), @@ -82,9 +82,9 @@ impl fmt::Debug for MonitorId { } } -impl MonitorId { +impl MonitorHandle { pub fn get_name(&self) -> Option { - let MonitorId(display_id) = *self; + let MonitorHandle(display_id) = *self; let screen_num = CGDisplay::new(display_id).model_number(); Some(format!("Monitor #{}", screen_num)) } @@ -95,7 +95,7 @@ impl MonitorId { } pub fn get_dimensions(&self) -> PhysicalSize { - let MonitorId(display_id) = *self; + let MonitorHandle(display_id) = *self; let display = CGDisplay::new(display_id); let height = display.pixels_high(); let width = display.pixels_wide(); diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index 30a305c44d..c1c25d943e 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -44,7 +44,7 @@ use os::macos::{ActivationPolicy, WindowExt}; use platform_impl::platform::{ffi, util}; use platform_impl::platform::event_loop::{EventLoop, Shared}; use platform_impl::platform::view::{new_view, set_ime_spot}; -use window::MonitorId as RootMonitorId; +use window::MonitorHandle as RootMonitorHandle; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Id(pub usize); @@ -537,13 +537,13 @@ pub struct Window2 { unsafe impl Send for Window2 {} unsafe impl Sync for Window2 {} -unsafe fn get_current_monitor(window: id) -> RootMonitorId { +unsafe fn get_current_monitor(window: id) -> RootMonitorHandle { let screen: id = msg_send![window, screen]; let desc = NSScreen::deviceDescription(screen); let key = IdRef::new(NSString::alloc(nil).init_str("NSScreenNumber")); let value = NSDictionary::valueForKey_(desc, *key); let display_id = msg_send![value, unsignedIntegerValue]; - RootMonitorId { inner: EventLoop::make_monitor_from_display(display_id) } + RootMonitorHandle { inner: EventLoop::make_monitor_from_display(display_id) } } impl Drop for Window2 { @@ -1084,7 +1084,7 @@ impl Window2 { #[inline] /// TODO: Right now set_fullscreen do not work on switching monitors /// in fullscreen mode - pub fn set_fullscreen(&self, monitor: Option) { + pub fn set_fullscreen(&self, monitor: Option) { let state = &self.delegate.state; let current = { let win_attribs = state.win_attribs.borrow_mut(); @@ -1186,7 +1186,7 @@ impl Window2 { } #[inline] - pub fn get_current_monitor(&self) -> RootMonitorId { + pub fn get_current_monitor(&self) -> RootMonitorHandle { unsafe { self::get_current_monitor(*self.window) } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 5cafe32d04..d28f2ac0b2 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -41,7 +41,7 @@ use winapi::um::{winuser, winbase, ole2, processthreadsapi, commctrl, libloadera use winapi::um::winnt::{LONG, LPCSTR, SHORT}; use window::WindowId as RootWindowId; -use monitor::MonitorId; +use monitor::MonitorHandle; use event_loop::{ControlFlow, EventLoop as RootEventLoop, EventLoopClosed}; use dpi::{LogicalPosition, LogicalSize, PhysicalSize}; use event::{DeviceEvent, Touch, TouchPhase, StartCause, KeyboardInput, Event, WindowEvent}; @@ -91,7 +91,7 @@ pub struct WindowState { // This is different from the value in `SavedWindowInfo`! That one represents the DPI saved upon entering // fullscreen. This will always be the most recent DPI for the window. pub dpi_factor: f64, - pub fullscreen: Option, + pub fullscreen: Option, pub window_icon: Option, pub taskbar_icon: Option, pub decorations: bool, diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index f6c5ed6294..5e989bf0b0 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -4,7 +4,7 @@ use winapi; use winapi::shared::windef::HWND; pub use self::event_loop::{EventLoop, EventLoopProxy}; -pub use self::monitor::MonitorId; +pub use self::monitor::MonitorHandle; pub use self::window::Window; use window::Icon; diff --git a/src/platform_impl/windows/monitor.rs b/src/platform_impl/windows/monitor.rs index 67c4aa062e..19c981ec28 100644 --- a/src/platform_impl/windows/monitor.rs +++ b/src/platform_impl/windows/monitor.rs @@ -11,9 +11,9 @@ use dpi::{PhysicalPosition, PhysicalSize}; use platform_impl::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi}; use platform_impl::platform::window::Window; -/// Win32 implementation of the main `MonitorId` object. +/// Win32 implementation of the main `MonitorHandle` object. #[derive(Debug, Clone)] -pub struct MonitorId { +pub struct MonitorHandle { /// Monitor handle. hmonitor: HMonitor, /// The system name of the monitor. @@ -45,13 +45,13 @@ unsafe extern "system" fn monitor_enum_proc( _place: LPRECT, data: LPARAM, ) -> BOOL { - let monitors = data as *mut VecDeque; - (*monitors).push_back(MonitorId::from_hmonitor(hmonitor)); + let monitors = data as *mut VecDeque; + (*monitors).push_back(MonitorHandle::from_hmonitor(hmonitor)); TRUE // continue enumeration } -pub fn get_available_monitors() -> VecDeque { - let mut monitors: VecDeque = VecDeque::new(); +pub fn get_available_monitors() -> VecDeque { + let mut monitors: VecDeque = VecDeque::new(); unsafe { winuser::EnumDisplayMonitors( ptr::null_mut(), @@ -63,38 +63,38 @@ pub fn get_available_monitors() -> VecDeque { monitors } -pub fn get_primary_monitor() -> MonitorId { +pub fn get_primary_monitor() -> MonitorHandle { const ORIGIN: POINT = POINT { x: 0, y: 0 }; let hmonitor = unsafe { winuser::MonitorFromPoint(ORIGIN, winuser::MONITOR_DEFAULTTOPRIMARY) }; - MonitorId::from_hmonitor(hmonitor) + MonitorHandle::from_hmonitor(hmonitor) } -pub fn get_current_monitor(hwnd: HWND) -> MonitorId { +pub fn get_current_monitor(hwnd: HWND) -> MonitorHandle { let hmonitor = unsafe { winuser::MonitorFromWindow(hwnd, winuser::MONITOR_DEFAULTTONEAREST) }; - MonitorId::from_hmonitor(hmonitor) + MonitorHandle::from_hmonitor(hmonitor) } impl EventLoop { // TODO: Investigate opportunities for caching - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { get_available_monitors() } - pub fn get_primary_monitor(&self) -> MonitorId { + pub fn get_primary_monitor(&self) -> MonitorHandle { get_primary_monitor() } } impl Window { - pub fn get_available_monitors(&self) -> VecDeque { + pub fn get_available_monitors(&self) -> VecDeque { get_available_monitors() } - pub fn get_primary_monitor(&self) -> MonitorId { + pub fn get_primary_monitor(&self) -> MonitorHandle { get_primary_monitor() } } @@ -115,7 +115,7 @@ fn get_monitor_info(hmonitor: HMONITOR) -> Result Self { let monitor_info = get_monitor_info(hmonitor).expect("`GetMonitorInfoW` failed"); let place = monitor_info.rcMonitor; @@ -123,7 +123,7 @@ impl MonitorId { (place.right - place.left) as u32, (place.bottom - place.top) as u32, ); - MonitorId { + MonitorHandle { hmonitor: HMonitor(hmonitor), monitor_name: util::wchar_ptr_to_string(monitor_info.szDevice.as_ptr()), primary: util::has_flag(monitor_info.dwFlags, winuser::MONITORINFOF_PRIMARY), diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index d1e2b0b217..79b2d23d0b 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -20,7 +20,7 @@ use winapi::um::winnt::{LONG, LPCWSTR}; use window::{CreationError, Icon, WindowAttributes, MouseCursor}; use dpi::{LogicalPosition, LogicalSize, PhysicalSize}; -use monitor::MonitorId as RootMonitorId; +use monitor::MonitorHandle as RootMonitorHandle; use platform_impl::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, WindowId}; use platform_impl::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi}; use platform_impl::platform::event_loop::{self, EventLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}; @@ -606,11 +606,11 @@ impl Window { } #[inline] - pub fn set_fullscreen(&self, monitor: Option) { + pub fn set_fullscreen(&self, monitor: Option) { let mut window_state_lock = self.window_state.lock(); unsafe { let monitor_rect = monitor.as_ref() - .map(|RootMonitorId{ ref inner }| { + .map(|RootMonitorHandle{ ref inner }| { let (x, y): (i32, i32) = inner.get_position().into(); let (width, height): (u32, u32) = inner.get_dimensions().into(); (x, y, width, height) @@ -772,8 +772,8 @@ impl Window { } #[inline] - pub fn get_current_monitor(&self) -> RootMonitorId { - RootMonitorId { + pub fn get_current_monitor(&self) -> RootMonitorHandle { + RootMonitorHandle { inner: monitor::get_current_monitor(self.window.0), } } diff --git a/src/window.rs b/src/window.rs index bd428809ef..eeed57aa36 100644 --- a/src/window.rs +++ b/src/window.rs @@ -3,7 +3,7 @@ use std::{fmt, error}; use platform_impl; use event_loop::EventLoop; -use monitor::{AvailableMonitorsIter, MonitorId}; +use monitor::{AvailableMonitorsIter, MonitorHandle}; use dpi::{LogicalPosition, LogicalSize}; pub use icon::*; @@ -93,7 +93,7 @@ pub struct WindowAttributes { /// Whether the window should be set as fullscreen upon creation. /// /// The default is `None`. - pub fullscreen: Option, + pub fullscreen: Option, /// The title of the window in the title bar. /// @@ -210,10 +210,10 @@ impl WindowBuilder { self } - /// Sets the window fullscreen state. None means a normal window, Some(MonitorId) + /// Sets the window fullscreen state. None means a normal window, Some(MonitorHandle) /// means a fullscreen window on that specific monitor #[inline] - pub fn with_fullscreen(mut self, monitor: Option) -> WindowBuilder { + pub fn with_fullscreen(mut self, monitor: Option) -> WindowBuilder { self.window.fullscreen = monitor; self } @@ -521,7 +521,7 @@ impl Window { /// Sets the window to fullscreen or back #[inline] - pub fn set_fullscreen(&self, monitor: Option) { + pub fn set_fullscreen(&self, monitor: Option) { self.window.set_fullscreen(monitor) } @@ -558,7 +558,7 @@ impl Window { /// Returns the monitor on which the window currently resides #[inline] - pub fn get_current_monitor(&self) -> MonitorId { + pub fn get_current_monitor(&self) -> MonitorHandle { self.window.get_current_monitor() } @@ -575,8 +575,8 @@ impl Window { /// /// This is the same as `EventLoop::get_primary_monitor`, and is provided for convenience. #[inline] - pub fn get_primary_monitor(&self) -> MonitorId { - MonitorId { inner: self.window.get_primary_monitor() } + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle { inner: self.window.get_primary_monitor() } } /// Returns an identifier unique to the window. diff --git a/tests/send_objects.rs b/tests/send_objects.rs index c2e890f865..d4402aaca3 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -19,5 +19,5 @@ fn ids_send() { // ensures that the various `..Id` types implement `Send` needs_send::(); needs_send::(); - needs_send::(); + needs_send::(); } From a654400e730400c2e3584be2f47153043b5b7efe Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 23 Aug 2018 21:06:19 -0400 Subject: [PATCH 20/40] Add CHANGELOG entry --- CHANGELOG.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cec5aef5d..07a1f7834c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,40 @@ # Unreleased +- Changes below are considered **breaking**. +- Change all occurrences of `EventsLoop` to `EventLoop`. +- Previously flat API is now exposed through `event`, `event_loop`, `monitor`, and `window` modules. +- `os` module changes: + - Renamed to `platform`. + - All traits now have platform-specific suffixes. + - Exposes new `desktop` module on Windows, Mac, and Linux. +- Changes to event loop types: + - `EventLoopProxy::wakeup` has been removed in favor of `send_event`. + - **Major:** New `run` method drives winit event loop. + - Returns `!` to ensure API behaves identically across all supported platforms. + - This allows `emscripten` implementation to work without lying about the API. + - `ControlFlow`'s variants have been replaced with `Wait`, `WaitUntil(Instant)`, `Poll`, and `Exit`. + - Is read after `EventsCleared` is processed. + - `Wait` waits until new events are available. + - `WaitUntil` waits until either new events are available or the provided time has been reached. + - `Poll` instantly resumes the event loop. + - `Exit` aborts the event loop. + - Takes a closure that implements `'static + FnMut(Event, &EventLoop, &mut ControlFlow)`. + - `&EventLoop` is provided to allow new `Window`s to be created. + - **Major:** `platform::desktop` module exposes `EventLoopExtDesktop` trait with `run_return` method. + - Behaves identically to `run`, but returns control flow to the calling context can take non-`'static` closures. + - `EventLoop`'s `poll_events` and `run_forever` methods have been removed in favor of `run` and `run_return`. +- Changes to events: + - Remove `Event::Awakened` in favor of `Event::UserEvent(T)`. + - Can be sent with `EventLoopProxy::send_event`. + - Rename `WindowEvent::Refresh` to `WindowEvent::RedrawRequested`. + - `RedrawRequested` can be sent by the user with the `Window::request_redraw` method. + - `EventLoop`, `EventLoopProxy`, and `Event` are now generic over `T`, for use in `UserEvent`. + - **Major:** Add `NewEvents(StartCause)`, `EventsCleared`, and `LoopDestroyed` variants to `Event`. + - `NewEvents` is emitted when new events are ready to be processed by event loop. + - `StartCause` describes why new events are available, with `ResumeTimeReached`, `Poll`, `WaitCancelled`, and `Init` (sent once at start of loop). + - `EventsCleared` is emitted when all available events have been processed. + - Can be used to perform logic that depends on all events being processed (e.g. an iteration of a game loop). + - `LoopDestroyed` is emitted when the `run` or `run_return` method is about to exit. +- Rename `MonitorId` to `MonitorHandle`. # Version 0.18.0 (2018-11-07) From 53370924b25da15ddd172173150b228065324864 Mon Sep 17 00:00:00 2001 From: Osspial Date: Sun, 26 Aug 2018 21:55:51 -0400 Subject: [PATCH 21/40] Improve WaitUntil timer precision --- src/platform_impl/windows/event_loop.rs | 211 ++++++++++++++---------- src/platform_impl/windows/window.rs | 1 - 2 files changed, 125 insertions(+), 87 deletions(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index d28f2ac0b2..ca238a2980 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -99,7 +99,6 @@ pub struct WindowState { pub maximized: bool, pub resizable: bool, pub mouse_buttons_down: u32, - pub modal_timer_handle: UINT_PTR } impl WindowState { @@ -190,7 +189,8 @@ impl EventLoop { event_loop: self, control_flow: ControlFlow::default(), runner_state: RunnerState::New, - modal_loop_data: None, + in_modal_loop: false, + modal_redraw_window: self.thread_msg_target, event_handler: unsafe { // Transmute used to erase lifetimes. mem::transmute::< @@ -213,8 +213,6 @@ impl EventLoop { } unsafe { - let timer_handle = winuser::SetTimer(ptr::null_mut(), 0, 0x7FFFFFFF, None); - let mut msg = mem::uninitialized(); let mut msg_unprocessed = false; @@ -241,16 +239,7 @@ impl EventLoop { msg_unprocessed = true; } ControlFlow::WaitUntil(resume_time) => { - let now = Instant::now(); - if now <= resume_time { - let duration = resume_time - now; - winuser::SetTimer(ptr::null_mut(), timer_handle, dur2timeout(duration), None); - if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { - break 'main - } - winuser::SetTimer(ptr::null_mut(), timer_handle, 0x7FFFFFFF, None); - msg_unprocessed = true; - } + wait_until_time_or_msg(resume_time); }, ControlFlow::Poll => () } @@ -286,15 +275,11 @@ pub(crate) struct EventLoopRunner { event_loop: *const EventLoop, control_flow: ControlFlow, runner_state: RunnerState, - modal_loop_data: Option, + modal_redraw_window: HWND, + in_modal_loop: bool, event_handler: *mut FnMut(Event, &RootEventLoop, &mut ControlFlow) } -struct ModalLoopData { - hwnd: HWND, - timer_handle: UINT_PTR -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum RunnerState { /// The event loop has just been created, and an `Init` event must be sent. @@ -363,12 +348,18 @@ impl EventLoopRunner { } unsafe fn process_event(&mut self, event: Event) { - // If we're in the middle of a modal loop, only set the timer for zero if it hasn't been - // reset in a prior call to `process_event`. - if let Some(ModalLoopData{hwnd, timer_handle}) = self.modal_loop_data { - if self.runner_state != RunnerState::HandlingEvents { - winuser::SetTimer(hwnd, timer_handle, 0, None); - } + // If we're in the modal loop, we need to have some mechanism for finding when the event + // queue has been cleared so we can call `events_cleared`. Windows doesn't give any utilities + // for doing this, but it DOES guarantee that WM_PAINT will only occur after input events have + // been processed. So, we send WM_PAINT to a dummy window which calls `events_cleared` when + // the events queue has been emptied. + if self.in_modal_loop { + winuser::RedrawWindow( + self.modal_redraw_window, + ptr::null(), + ptr::null_mut(), + winuser::RDW_INTERNALPAINT + ); } // If new event processing has to be done (i.e. call NewEvents or defer), do it. If we're @@ -475,6 +466,29 @@ impl EventLoopRunner { } } +// Returns true if the wait time was reached, and false if a message must be processed. +unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool { + let mut msg = mem::uninitialized(); + let now = Instant::now(); + if now <= wait_until { + // MsgWaitForMultipleObjects tends to overshoot just a little bit. We subtract 1 millisecond + // from the requested time and spinlock for the remainder to compensate for that. + winuser::MsgWaitForMultipleObjects( + 0, + ptr::null(), + 1, + dur2timeout(wait_until - now).saturating_sub(1), + winuser::QS_ALLINPUT + ); + while Instant::now() < wait_until { + if 0 != winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) { + return false; + } + } + } + + return true; +} // Implementation taken from https://github.com/rust-lang/rust/blob/db5476571d9b27c862b95c1e64764b0ac8980e23/src/libstd/sys/windows/mod.rs fn dur2timeout(dur: Duration) -> DWORD { // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the @@ -648,7 +662,7 @@ lazy_static! { fn thread_event_target_window(event_loop_runner: EventLoopRunnerShared) -> (HWND, Sender) { unsafe { let window = winuser::CreateWindowExW( - 0, + winuser::WS_EX_NOACTIVATE | winuser::WS_EX_TRANSPARENT | winuser::WS_EX_LAYERED, THREAD_EVENT_TARGET_WINDOW_CLASS.as_ptr(), ptr::null_mut(), 0, @@ -659,6 +673,14 @@ fn thread_event_target_window(event_loop_runner: EventLoopRunnerShared) -> libloaderapi::GetModuleHandleW(ptr::null()), ptr::null_mut() ); + winuser::SetWindowLongPtrW( + window, + winuser::GWL_STYLE, + // The window technically has to be visible to receive WM_PAINT messages (which are used + // for delivering events during resizes), but it isn't displayed to the user because of + // the LAYERED style. + (winuser::WS_VISIBLE | winuser::WS_POPUP) as _ + ); let (tx, rx) = crossbeam_channel::unbounded(); @@ -726,67 +748,20 @@ unsafe extern "system" fn public_window_callback( let subclass_input = &mut*(subclass_input_ptr as *mut SubclassInput); match msg { - winuser::WM_SYSCOMMAND => { - { - let mut window_state = subclass_input.window_state.lock(); - if window_state.modal_timer_handle == 0 { - window_state.modal_timer_handle = winuser::SetTimer(window, 0, 0x7FFFFFFF, None); - } - } - commctrl::DefSubclassProc(window, msg, wparam, lparam) - } winuser::WM_ENTERSIZEMOVE => { - let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle; - if let ELRSharedOption::Runner(runner) = *subclass_input.event_loop_runner.borrow_mut() { - (*runner).modal_loop_data = Some(ModalLoopData { - hwnd: window, - timer_handle: modal_timer_handle - }); + let runner = subclass_input.event_loop_runner.borrow_mut(); + if let ELRSharedOption::Runner(runner) = *runner { + (*runner).in_modal_loop = true; } - winuser::SetTimer(window, modal_timer_handle, 0, None); 0 }, winuser::WM_EXITSIZEMOVE => { - let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle; - if let ELRSharedOption::Runner(runner) = *subclass_input.event_loop_runner.borrow_mut() { - (*runner).modal_loop_data = None; + let runner = subclass_input.event_loop_runner.borrow_mut(); + if let ELRSharedOption::Runner(runner) = *runner { + (*runner).in_modal_loop = false; } - winuser::SetTimer(window, modal_timer_handle, 0x7FFFFFFF, None); 0 }, - winuser::WM_TIMER => { - let modal_timer_handle = subclass_input.window_state.lock().modal_timer_handle; - if wparam == modal_timer_handle { - let runner = subclass_input.event_loop_runner.borrow_mut(); - if let ELRSharedOption::Runner(runner) = *runner { - let runner = &mut *runner; - if runner.modal_loop_data.is_some() { - runner.events_cleared(); - match runner.control_flow { - ControlFlow::Exit => (), - ControlFlow::Wait => { - winuser::SetTimer(window, modal_timer_handle, 0x7FFFFFFF, None); - }, - ControlFlow::WaitUntil(resume_time) => { - let now = Instant::now(); - let duration = match now <= resume_time { - true => dur2timeout(resume_time - now), - false => 0 - }; - winuser::SetTimer(window, modal_timer_handle, duration, None); - }, - ControlFlow::Poll => { - winuser::SetTimer(window, modal_timer_handle, 0, None); - } - } - - runner.new_events(); - } - } - } - 0 - } - winuser::WM_NCCREATE => { enable_non_client_dpi_scaling(window); commctrl::DefSubclassProc(window, msg, wparam, lparam) @@ -804,12 +779,6 @@ unsafe extern "system" fn public_window_callback( winuser::WM_DESTROY => { use event::WindowEvent::Destroyed; ole2::RevokeDragDrop(window); - { - let window_state = subclass_input.window_state.lock(); - if window_state.modal_timer_handle != 0 { - winuser::KillTimer(window, window_state.modal_timer_handle); - } - } subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: Destroyed @@ -1520,6 +1489,76 @@ unsafe extern "system" fn thread_event_target_callback( drop(subclass_input); 0 }, + // Because WM_PAINT comes after all other messages, we use it during modal loops to detect + // when the event queue has been emptied. See `process_event` for more details. + winuser::WM_PAINT => { + winuser::ValidateRect(window, ptr::null()); + let queue_call_again = || { + winuser::RedrawWindow( + window, + ptr::null(), + ptr::null_mut(), + winuser::RDW_INTERNALPAINT + ); + }; + let in_modal_loop = { + let runner = subclass_input.event_loop_runner.borrow_mut(); + if let ELRSharedOption::Runner(runner) = *runner { + (*runner).in_modal_loop + } else { + false + } + }; + if in_modal_loop { + let mut msg = mem::uninitialized(); + loop { + if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) { + break; + } + // Clear all paint/timer messages from the queue before sending the events cleared message. + match msg.message { + // Flush the event queue of WM_PAINT messages. + winuser::WM_PAINT | + winuser::WM_TIMER => { + // Remove the message from the message queue. + winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1); + + if msg.hwnd != window { + winuser::TranslateMessage(&mut msg); + winuser::DispatchMessageW(&mut msg); + } + }, + // If the message isn't one of those three, it may be handled by the modal + // loop so we should return control flow to it. + _ => { + queue_call_again(); + return 0; + } + } + } + + let runner = subclass_input.event_loop_runner.borrow_mut(); + if let ELRSharedOption::Runner(runner) = *runner { + let runner = &mut *runner; + runner.events_cleared(); + match runner.control_flow { + // Waiting is handled by the modal loop. + ControlFlow::Exit | + ControlFlow::Wait => runner.new_events(), + ControlFlow::WaitUntil(resume_time) => { + wait_until_time_or_msg(resume_time); + runner.new_events(); + queue_call_again(); + }, + ControlFlow::Poll => { + runner.new_events(); + queue_call_again(); + } + } + } + } + 0 + } _ if msg == *USER_EVENT_MSG_ID => { if let Ok(event) = subclass_input.user_event_receiver.recv() { subclass_input.send_event(Event::UserEvent(event)); diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 79b2d23d0b..e50856bacd 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -1061,7 +1061,6 @@ unsafe fn init( mouse_in_window: false, saved_window_info: None, mouse_buttons_down: 0, - modal_timer_handle: 0 }; // Creating a mutex to track the current window state Arc::new(Mutex::new(window_state)) From 70722cc4c322e3e599b3a03bce5058a5d433970b Mon Sep 17 00:00:00 2001 From: Osspial Date: Wed, 5 Sep 2018 19:58:52 -1100 Subject: [PATCH 22/40] When SendEvent is called during event closure, buffer events --- src/platform_impl/windows/event_loop.rs | 80 ++++++++++++++----------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index ca238a2980..60a493995e 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -20,6 +20,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use std::rc::Rc; use std::cell::RefCell; +use std::collections::VecDeque; use parking_lot::Mutex; use crossbeam_channel::{self, Sender, Receiver}; @@ -122,11 +123,7 @@ pub(crate) struct SubclassInput { impl SubclassInput { unsafe fn send_event(&self, event: Event) { - let mut runner = self.event_loop_runner.borrow_mut(); - match *runner { - ELRSharedOption::Runner(runner) => (*runner).process_event(event), - ELRSharedOption::Buffer(ref mut buffer) => buffer.push(event) - } + self.event_loop_runner.send_event(event); } } @@ -137,11 +134,7 @@ struct ThreadMsgTargetSubclassInput { impl ThreadMsgTargetSubclassInput { unsafe fn send_event(&self, event: Event) { - let mut runner = self.event_loop_runner.borrow_mut(); - match *runner { - ELRSharedOption::Runner(runner) => (*runner).process_event(event), - ELRSharedOption::Buffer(ref mut buffer) => buffer.push(event) - } + self.event_loop_runner.send_event(event); } } @@ -163,7 +156,10 @@ impl EventLoop { become_dpi_aware(dpi_aware); let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; - let runner_shared = Rc::new(RefCell::new(ELRSharedOption::Buffer(vec![]))); + let runner_shared = Rc::new(ELRShared { + runner: RefCell::new(None), + buffer: RefCell::new(VecDeque::new()) + }); let (thread_msg_target, thread_msg_sender) = thread_event_target_window(runner_shared.clone()); EventLoop { @@ -201,15 +197,15 @@ impl EventLoop { }; { let runner_shared = self.runner_shared.clone(); - let mut runner_shared = runner_shared.borrow_mut(); - let mut event_buffer = vec![]; - if let ELRSharedOption::Buffer(ref mut buffer) = *runner_shared { - mem::swap(buffer, &mut event_buffer); - } - for event in event_buffer.drain(..) { - unsafe{ runner.process_event(event); } + let mut runner_ref = runner_shared.runner.borrow_mut(); + loop { + let event = runner_shared.buffer.borrow_mut().pop_front(); + match event { + Some(e) => unsafe{ runner.process_event(e); }, + None => break + } } - *runner_shared = ELRSharedOption::Runner(&mut runner); + *runner_ref = Some(&mut runner); } unsafe { @@ -247,7 +243,7 @@ impl EventLoop { } unsafe{ runner.call_event_handler(Event::LoopDestroyed) } - *self.runner_shared.borrow_mut() = ELRSharedOption::Buffer(vec![]); + *self.runner_shared.runner.borrow_mut() = None; } pub fn create_proxy(&self) -> EventLoopProxy { @@ -266,10 +262,10 @@ impl EventLoop { } } -pub(crate) type EventLoopRunnerShared = Rc>>; -pub(crate) enum ELRSharedOption { - Runner(*mut EventLoopRunner), - Buffer(Vec>) +pub(crate) type EventLoopRunnerShared = Rc>; +pub(crate) struct ELRShared { + runner: RefCell>>, + buffer: RefCell>> } pub(crate) struct EventLoopRunner { event_loop: *const EventLoop, @@ -280,6 +276,18 @@ pub(crate) struct EventLoopRunner { event_handler: *mut FnMut(Event, &RootEventLoop, &mut ControlFlow) } +impl ELRShared { + unsafe fn send_event(&self, event: Event) { + if let Ok(runner_ref) = self.runner.try_borrow_mut() { + if let Some(runner) = *runner_ref { + (*runner).process_event(event); + return; + } + } + self.buffer.borrow_mut().push_back(event) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum RunnerState { /// The event loop has just been created, and an `Init` event must be sent. @@ -749,15 +757,15 @@ unsafe extern "system" fn public_window_callback( match msg { winuser::WM_ENTERSIZEMOVE => { - let runner = subclass_input.event_loop_runner.borrow_mut(); - if let ELRSharedOption::Runner(runner) = *runner { + let runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(runner) = *runner { (*runner).in_modal_loop = true; } 0 }, winuser::WM_EXITSIZEMOVE => { - let runner = subclass_input.event_loop_runner.borrow_mut(); - if let ELRSharedOption::Runner(runner) = *runner { + let runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(runner) = *runner { (*runner).in_modal_loop = false; } 0 @@ -791,8 +799,8 @@ unsafe extern "system" fn public_window_callback( _ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => { use event::WindowEvent::RedrawRequested; - let runner = subclass_input.event_loop_runner.borrow_mut(); - if let ELRSharedOption::Runner(runner) = *runner { + let runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(runner) = *runner { let runner = &mut *runner; match runner.runner_state { RunnerState::Idle(..) | @@ -814,8 +822,8 @@ unsafe extern "system" fn public_window_callback( let mut send_event = false; { - let runner = subclass_input.event_loop_runner.borrow_mut(); - if let ELRSharedOption::Runner(runner) = *runner { + let runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(runner) = *runner { let runner = &mut *runner; match runner.runner_state { RunnerState::Idle(..) | @@ -1502,8 +1510,8 @@ unsafe extern "system" fn thread_event_target_callback( ); }; let in_modal_loop = { - let runner = subclass_input.event_loop_runner.borrow_mut(); - if let ELRSharedOption::Runner(runner) = *runner { + let runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(runner) = *runner { (*runner).in_modal_loop } else { false @@ -1537,8 +1545,8 @@ unsafe extern "system" fn thread_event_target_callback( } } - let runner = subclass_input.event_loop_runner.borrow_mut(); - if let ELRSharedOption::Runner(runner) = *runner { + let runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(runner) = *runner { let runner = &mut *runner; runner.events_cleared(); match runner.control_flow { From bf7bfa82ebb5d6ae110ce0492c124ef462945f85 Mon Sep 17 00:00:00 2001 From: Osspial Date: Wed, 5 Sep 2018 22:36:05 -0400 Subject: [PATCH 23/40] Fix resize lag when waiting in some situations --- src/platform_impl/windows/event_loop.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 60a493995e..0c89a438dd 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -37,7 +37,7 @@ use winapi::shared::minwindef::{ WPARAM, }; use winapi::shared::windef::{HWND, POINT, RECT}; -use winapi::shared::windowsx; +use winapi::shared::{windowsx, winerror}; use winapi::um::{winuser, winbase, ole2, processthreadsapi, commctrl, libloaderapi}; use winapi::um::winnt::{LONG, LPCSTR, SHORT}; @@ -481,16 +481,19 @@ unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool { if now <= wait_until { // MsgWaitForMultipleObjects tends to overshoot just a little bit. We subtract 1 millisecond // from the requested time and spinlock for the remainder to compensate for that. - winuser::MsgWaitForMultipleObjects( + let resume_reason = winuser::MsgWaitForMultipleObjectsEx( 0, ptr::null(), - 1, dur2timeout(wait_until - now).saturating_sub(1), - winuser::QS_ALLINPUT + winuser::QS_ALLEVENTS, + winuser::MWMO_INPUTAVAILABLE ); - while Instant::now() < wait_until { - if 0 != winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) { - return false; + + if resume_reason == winerror::WAIT_TIMEOUT { + while Instant::now() < wait_until { + if 0 != winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) { + return false; + } } } } From 8ed575ff4a4f0961bb2e784bda1ae109c6bd37b7 Mon Sep 17 00:00:00 2001 From: Osspial Date: Sun, 9 Sep 2018 00:19:53 -0400 Subject: [PATCH 24/40] Update send test and errors that broke some examples/APIs --- examples/handling_close.rs | 3 +-- src/platform_impl/windows/window.rs | 2 +- tests/send_objects.rs | 6 ++++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/handling_close.rs b/examples/handling_close.rs index a2db1216b9..31f17da33e 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -17,6 +17,7 @@ fn main() { event_loop.run(move |event, _, control_flow| { use winit::event::ElementState::Released; use winit::event::VirtualKeyCode::{N, Y}; + *control_flow = ControlFlow::Wait; match event { Event::WindowEvent { event, .. } => match event { @@ -71,7 +72,5 @@ fn main() { }, _ => (), } - - *control_flow = ControlFlow::Wait; }); } diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index e50856bacd..8140cc19ee 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -448,6 +448,7 @@ impl Window { let window_state_lock = self.window_state.lock(); // We don't want to increment/decrement the display count more than once! if hide == window_state_lock.cursor_hidden { return; } + drop(window_state_lock); let (tx, rx) = channel(); let window_state = Arc::clone(&self.window_state); self.thread_executor.execute_in_thread(move || { @@ -455,7 +456,6 @@ impl Window { window_state.lock().cursor_hidden = hide; let _ = tx.send(()); }); - drop(window_state_lock); rx.recv().unwrap() } diff --git a/tests/send_objects.rs b/tests/send_objects.rs index d4402aaca3..9220203fd4 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -4,8 +4,10 @@ fn needs_send() {} #[test] fn event_loop_proxy_send() { - // ensures that `winit::EventLoopProxy` implements `Send` - needs_send::>(); + fn is_send() { + // ensures that `winit::EventLoopProxy` implements `Send` + needs_send::>(); + } } #[test] From 5068ff4ee152bfe93c9190235f02d001202feb88 Mon Sep 17 00:00:00 2001 From: Osspial Date: Sun, 9 Sep 2018 14:14:28 -0400 Subject: [PATCH 25/40] Improve clarity/fix typos in docs --- src/event_loop.rs | 30 +++++++++++++++++++++--------- src/platform/unix.rs | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/event_loop.rs b/src/event_loop.rs index 585963ef4c..2d484a900a 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -25,10 +25,10 @@ use monitor::{AvailableMonitorsIter, MonitorHandle}; /// /// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs. /// -/// Note that the `EventLoop` cannot be shared accross threads (due to platform-dependant logic -/// forbiding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the +/// Note that the `EventLoop` cannot be shared across threads (due to platform-dependant logic +/// forbidding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the /// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the -/// `EventLoopProxy` allows you to wakeup an `EventLoop` from an other thread. +/// `EventLoopProxy` allows you to wake up an `EventLoop` from an other thread. pub struct EventLoop { pub(crate) event_loop: platform_impl::EventLoop, pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync @@ -43,22 +43,29 @@ impl std::fmt::Debug for EventLoop { /// Set by the user callback given to the `EventLoop::run` method. /// /// Indicates the desired behavior of the event loop after [`Event::EventsCleared`][events_cleared] -/// is emitted. +/// is emitted. Defaults to `Poll`. +/// +/// ## Persistency +/// Almost every change is persistent between multiple calls to the event loop closure within a +/// given run loop. The only exception to this is `Exit` which, once set, cannot be unset. Changes +/// are **not** persistent between multiple calls to `run_return` - issuing a new call will reset +/// the control flow to `Poll`. /// /// [events_cleared]: ../event/enum.Event.html#variant.EventsCleared #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ControlFlow { + /// When the current loop iteration finishes, immediately begin a new iteration regardless of + /// whether or not new events are available to process. + Poll, /// When the current loop iteration finishes, suspend the thread until another event arrives. Wait, /// When the current loop iteration finishes, suspend the thread until either another event /// arrives or the given time is reached. WaitUntil(Instant), - /// When the current loop iteration finishes, immediately begin a new iteration regardless of - /// whether or not new events are available to process. - Poll, - /// Send a `LoopDestroyed` event and stop the event loop. Once set, `control_flow` cannot be - /// changed from `Exit`. + /// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set, + /// `control_flow` cannot be changed from `Exit`, and any future attempts to do so will result + /// in the `control_flow` parameter being reset to `Exit`. Exit } @@ -109,7 +116,12 @@ impl EventLoop { /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to /// access any data from the calling context. /// + /// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the + /// event loop's behavior. + /// /// Any values not passed to this function will *not* be dropped. + /// + /// [`ControlFlow`]: ./enum.ControlFlow.html #[inline] pub fn run(self, event_handler: F) -> ! where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow) diff --git a/src/platform/unix.rs b/src/platform/unix.rs index f611a4f7cc..0073947ab7 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -25,7 +25,7 @@ pub use platform_impl::x11; pub use platform_impl::XNotSupported; pub use platform_impl::x11::util::WindowType as XWindowType; -/// Additional methods on `EventLoop` that are specific to Linux. +/// Additional methods on `EventLoop` that are specific to Unix. pub trait EventLoopExtUnix { /// Builds a new `EventLoop` that is forced to use X11. fn new_x11() -> Result From bb6ab1bb6e9595e90f1915fdde7e23904f2ba594 Mon Sep 17 00:00:00 2001 From: Osspial Date: Sun, 9 Sep 2018 14:28:16 -0400 Subject: [PATCH 26/40] Fix unreachable panic after setting ControlFlow to Poll during some RedrawRequested events. --- src/platform_impl/windows/event_loop.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 0c89a438dd..5e89740cdb 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -400,7 +400,9 @@ impl EventLoopRunner { }; self.call_event_handler(Event::NewEvents(start_cause)); }, - ControlFlow::Poll | + // This can be reached if the control flow is changed to poll during a `RedrawRequested` + // that was sent after `EventsCleared`. + ControlFlow::Poll => self.call_event_handler(Event::NewEvents(StartCause::Poll)), ControlFlow::Exit => unreachable!() } } From 8299eb2f03773a34079c61fc8adb51405aafc467 Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 13 Sep 2018 22:39:40 -0400 Subject: [PATCH 27/40] Fix crash when running in release mode --- src/platform_impl/windows/event_loop.rs | 98 +++++++++++++------------ 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 5e89740cdb..c42c2f8f39 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -205,7 +205,11 @@ impl EventLoop { None => break } } - *runner_ref = Some(&mut runner); + *runner_ref = Some(runner); + } + + macro_rules! runner { + () => {{ self.runner_shared.runner.borrow_mut().as_mut().unwrap() }}; } unsafe { @@ -213,7 +217,7 @@ impl EventLoop { let mut msg_unprocessed = false; 'main: loop { - runner.new_events(); + runner!().new_events(); loop { if !msg_unprocessed { if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { @@ -224,9 +228,9 @@ impl EventLoop { winuser::DispatchMessageW(&mut msg); msg_unprocessed = false; } - runner.events_cleared(); + runner!().events_cleared(); - match runner.control_flow { + match runner!().control_flow { ControlFlow::Exit => break 'main, ControlFlow::Wait => { if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { @@ -242,7 +246,7 @@ impl EventLoop { } } - unsafe{ runner.call_event_handler(Event::LoopDestroyed) } + unsafe{ runner!().call_event_handler(Event::LoopDestroyed) } *self.runner_shared.runner.borrow_mut() = None; } @@ -264,7 +268,7 @@ impl EventLoop { pub(crate) type EventLoopRunnerShared = Rc>; pub(crate) struct ELRShared { - runner: RefCell>>, + runner: RefCell>>, buffer: RefCell>> } pub(crate) struct EventLoopRunner { @@ -278,9 +282,9 @@ pub(crate) struct EventLoopRunner { impl ELRShared { unsafe fn send_event(&self, event: Event) { - if let Ok(runner_ref) = self.runner.try_borrow_mut() { - if let Some(runner) = *runner_ref { - (*runner).process_event(event); + if let Ok(mut runner_ref) = self.runner.try_borrow_mut() { + if let Some(ref mut runner) = *runner_ref { + runner.process_event(event); return; } } @@ -378,12 +382,14 @@ impl EventLoopRunner { // deferred. if let RunnerState::DeferredNewEvents(wait_start) = self.runner_state { match self.control_flow { - ControlFlow::Wait => self.call_event_handler( - Event::NewEvents(StartCause::WaitCancelled { - start: wait_start, - requested_resume: None - }) - ), + ControlFlow::Wait => { + self.call_event_handler( + Event::NewEvents(StartCause::WaitCancelled { + start: wait_start, + requested_resume: None + }) + ) + }, ControlFlow::WaitUntil(resume_time) => { let start_cause = match Instant::now() >= resume_time { // If the current time is later than the requested resume time, the resume time @@ -402,7 +408,9 @@ impl EventLoopRunner { }, // This can be reached if the control flow is changed to poll during a `RedrawRequested` // that was sent after `EventsCleared`. - ControlFlow::Poll => self.call_event_handler(Event::NewEvents(StartCause::Poll)), + ControlFlow::Poll => { + self.call_event_handler(Event::NewEvents(StartCause::Poll)) + }, ControlFlow::Exit => unreachable!() } } @@ -455,23 +463,19 @@ impl EventLoopRunner { } unsafe fn call_event_handler(&mut self, event: Event) { - if self.event_handler != mem::zeroed() { - match event { - Event::NewEvents(_) => (*self.event_loop).trigger_newevents_on_redraw.store(true, Ordering::Relaxed), - Event::EventsCleared => (*self.event_loop).trigger_newevents_on_redraw.store(false, Ordering::Relaxed), - _ => () - } + match event { + Event::NewEvents(_) => (*self.event_loop).trigger_newevents_on_redraw.store(true, Ordering::Relaxed), + Event::EventsCleared => (*self.event_loop).trigger_newevents_on_redraw.store(false, Ordering::Relaxed), + _ => () + } - assert_eq!(mem::size_of::>(), mem::size_of::>()); - let event_loop_ref = &*(self.event_loop as *const RootEventLoop); + assert_eq!(mem::size_of::>(), mem::size_of::>()); + let event_loop_ref = &*(self.event_loop as *const RootEventLoop); - if self.control_flow != ControlFlow::Exit { - (*self.event_handler)(event, event_loop_ref, &mut self.control_flow); - } else { - (*self.event_handler)(event, event_loop_ref, &mut ControlFlow::Exit); - } + if self.control_flow != ControlFlow::Exit { + (*self.event_handler)(event, event_loop_ref, &mut self.control_flow); } else { - panic!("Tried to call event handler with null handler"); + (*self.event_handler)(event, event_loop_ref, &mut ControlFlow::Exit); } } } @@ -762,16 +766,16 @@ unsafe extern "system" fn public_window_callback( match msg { winuser::WM_ENTERSIZEMOVE => { - let runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(runner) = *runner { - (*runner).in_modal_loop = true; + let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(ref mut runner) = *runner { + runner.in_modal_loop = true; } 0 }, winuser::WM_EXITSIZEMOVE => { - let runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(runner) = *runner { - (*runner).in_modal_loop = false; + let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(ref mut runner) = *runner { + runner.in_modal_loop = false; } 0 }, @@ -804,9 +808,8 @@ unsafe extern "system" fn public_window_callback( _ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => { use event::WindowEvent::RedrawRequested; - let runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(runner) = *runner { - let runner = &mut *runner; + let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(ref mut runner) = *runner { match runner.runner_state { RunnerState::Idle(..) | RunnerState::DeferredNewEvents(..) => runner.call_event_handler(Event::WindowEvent { @@ -827,9 +830,8 @@ unsafe extern "system" fn public_window_callback( let mut send_event = false; { - let runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(runner) = *runner { - let runner = &mut *runner; + let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(ref mut runner) = *runner { match runner.runner_state { RunnerState::Idle(..) | RunnerState::DeferredNewEvents(..) => runner.call_event_handler(event()), @@ -1154,7 +1156,8 @@ unsafe extern "system" fn public_window_callback( event, }); - commctrl::DefSubclassProc(window, msg, wparam, lparam) + 0 + // commctrl::DefSubclassProc(window, msg, wparam, lparam) }, winuser::WM_INPUT => { @@ -1516,8 +1519,8 @@ unsafe extern "system" fn thread_event_target_callback( }; let in_modal_loop = { let runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(runner) = *runner { - (*runner).in_modal_loop + if let Some(ref runner) = *runner { + runner.in_modal_loop } else { false } @@ -1550,9 +1553,8 @@ unsafe extern "system" fn thread_event_target_callback( } } - let runner = subclass_input.event_loop_runner.runner.borrow_mut(); - if let Some(runner) = *runner { - let runner = &mut *runner; + let mut runner = subclass_input.event_loop_runner.runner.borrow_mut(); + if let Some(ref mut runner) = *runner { runner.events_cleared(); match runner.control_flow { // Waiting is handled by the modal loop. From 92ac3d6ac7915923c22c380cc3a74c5f3830708e Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 8 Nov 2018 23:46:41 -0500 Subject: [PATCH 28/40] Remove crossbeam dependency and make drop events work again --- Cargo.toml | 3 - src/event_loop.rs | 2 +- src/lib.rs | 3 - src/platform_impl/windows/drop_handler.rs | 9 ++- src/platform_impl/windows/event_loop.rs | 87 +++++++++++++---------- src/platform_impl/windows/window.rs | 10 ++- src/window.rs | 4 +- 7 files changed, 64 insertions(+), 54 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 11641f863a..dc9ac5598a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,9 +35,6 @@ cocoa = "0.18.4" core-foundation = "0.6" core-graphics = "0.17.3" -[target.'cfg(target_os = "windows")'.dependencies.crossbeam-channel] -version = "0.3" - [target.'cfg(target_os = "windows")'.dependencies.winapi] version = "0.3.6" features = [ diff --git a/src/event_loop.rs b/src/event_loop.rs index 2d484a900a..efd14aea62 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -29,7 +29,7 @@ use monitor::{AvailableMonitorsIter, MonitorHandle}; /// forbidding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the /// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the /// `EventLoopProxy` allows you to wake up an `EventLoop` from an other thread. -pub struct EventLoop { +pub struct EventLoop { pub(crate) event_loop: platform_impl::EventLoop, pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync } diff --git a/src/lib.rs b/src/lib.rs index 48972433a5..86323be6b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,9 +89,6 @@ extern crate serde; #[cfg(target_os = "windows")] extern crate winapi; -#[cfg(target_os = "windows")] -#[macro_use] -extern crate crossbeam_channel; #[cfg(any(target_os = "macos", target_os = "ios"))] #[macro_use] extern crate objc; diff --git a/src/platform_impl/windows/drop_handler.rs b/src/platform_impl/windows/drop_handler.rs index 188d7be0c0..44034b3c76 100644 --- a/src/platform_impl/windows/drop_handler.rs +++ b/src/platform_impl/windows/drop_handler.rs @@ -3,7 +3,6 @@ use std::os::windows::ffi::OsStringExt; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use std::{mem, ptr}; -use crossbeam_channel::Sender; use winapi::ctypes::c_void; use winapi::shared::guiddef::REFIID; @@ -25,7 +24,7 @@ pub struct FileDropHandlerData { pub interface: IDropTarget, refcount: AtomicUsize, window: HWND, - // event_sender: Sender> + send_event: Box)> } pub struct FileDropHandler { @@ -34,14 +33,14 @@ pub struct FileDropHandler { #[allow(non_snake_case)] impl FileDropHandler { - pub fn new(window: HWND/*, event_sender: Sender>*/) -> FileDropHandler { + pub fn new(window: HWND, send_event: Box)>) -> FileDropHandler { let data = Box::new(FileDropHandlerData { interface: IDropTarget { lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl, }, refcount: AtomicUsize::new(1), window, - // event_sender, + send_event, }); FileDropHandler { data: Box::into_raw(data), @@ -187,7 +186,7 @@ impl FileDropHandler { impl FileDropHandlerData { fn send_event(&self, event: Event<()>) { - // self.event_sender.send(event).ok(); + (self.send_event)(event); } } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index c42c2f8f39..19fe8346d7 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -17,12 +17,12 @@ use winapi::shared::basetsd::UINT_PTR; use std::{mem, ptr}; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{self, Sender, Receiver}; use std::time::{Duration, Instant}; use std::rc::Rc; use std::cell::RefCell; use std::collections::VecDeque; use parking_lot::Mutex; -use crossbeam_channel::{self, Sender, Receiver}; use winapi::ctypes::c_int; use winapi::shared::minwindef::{ @@ -147,7 +147,7 @@ pub struct EventLoop { pub(crate) runner_shared: EventLoopRunnerShared, } -impl EventLoop { +impl EventLoop { pub fn new() -> EventLoop { Self::with_dpi_awareness(true) } @@ -181,27 +181,24 @@ impl EventLoop { where F: FnMut(Event, &RootEventLoop, &mut ControlFlow) { unsafe{ winuser::IsGUIThread(1); } - let mut runner = EventLoopRunner { - event_loop: self, - control_flow: ControlFlow::default(), - runner_state: RunnerState::New, - in_modal_loop: false, - modal_redraw_window: self.thread_msg_target, - event_handler: unsafe { - // Transmute used to erase lifetimes. - mem::transmute::< - &mut FnMut(Event, &RootEventLoop, &mut ControlFlow), - *mut FnMut(Event, &RootEventLoop, &mut ControlFlow) - >(&mut event_handler) + + assert_eq!(mem::size_of::>(), mem::size_of::>()); + let self_ptr = self as *const EventLoop; + + let mut runner = unsafe{ EventLoopRunner::new( + self, + move |event, control_flow| { + let event_loop_ref = &*(self_ptr as *const RootEventLoop); + event_handler(event, event_loop_ref, control_flow) } - }; + ) }; { let runner_shared = self.runner_shared.clone(); let mut runner_ref = runner_shared.runner.borrow_mut(); loop { let event = runner_shared.buffer.borrow_mut().pop_front(); match event { - Some(e) => unsafe{ runner.process_event(e); }, + Some(e) => { runner.process_event(e); }, None => break } } @@ -246,7 +243,7 @@ impl EventLoop { } } - unsafe{ runner!().call_event_handler(Event::LoopDestroyed) } + runner!().call_event_handler(Event::LoopDestroyed); *self.runner_shared.runner.borrow_mut() = None; } @@ -272,16 +269,16 @@ pub(crate) struct ELRShared { buffer: RefCell>> } pub(crate) struct EventLoopRunner { - event_loop: *const EventLoop, + trigger_newevents_on_redraw: Arc, control_flow: ControlFlow, runner_state: RunnerState, modal_redraw_window: HWND, in_modal_loop: bool, - event_handler: *mut FnMut(Event, &RootEventLoop, &mut ControlFlow) + event_handler: Box, &mut ControlFlow)> } impl ELRShared { - unsafe fn send_event(&self, event: Event) { + pub(crate) unsafe fn send_event(&self, event: Event) { if let Ok(mut runner_ref) = self.runner.try_borrow_mut() { if let Some(ref mut runner) = *runner_ref { runner.process_event(event); @@ -308,7 +305,23 @@ enum RunnerState { } impl EventLoopRunner { - unsafe fn new_events(&mut self) { + unsafe fn new(event_loop: &EventLoop, f: F) -> EventLoopRunner + where F: FnMut(Event, &mut ControlFlow) + { + EventLoopRunner { + trigger_newevents_on_redraw: event_loop.trigger_newevents_on_redraw.clone(), + control_flow: ControlFlow::default(), + runner_state: RunnerState::New, + in_modal_loop: false, + modal_redraw_window: event_loop.thread_msg_target, + event_handler: mem::transmute::< + Box, &mut ControlFlow)>, + Box, &mut ControlFlow)> + >(Box::new(f)) + } + } + + fn new_events(&mut self) { self.runner_state = match self.runner_state { // If we're already handling events or have deferred `NewEvents`, we don't need to do // do any processing. @@ -359,19 +372,21 @@ impl EventLoopRunner { }; } - unsafe fn process_event(&mut self, event: Event) { + fn process_event(&mut self, event: Event) { // If we're in the modal loop, we need to have some mechanism for finding when the event // queue has been cleared so we can call `events_cleared`. Windows doesn't give any utilities // for doing this, but it DOES guarantee that WM_PAINT will only occur after input events have // been processed. So, we send WM_PAINT to a dummy window which calls `events_cleared` when // the events queue has been emptied. if self.in_modal_loop { - winuser::RedrawWindow( - self.modal_redraw_window, - ptr::null(), - ptr::null_mut(), - winuser::RDW_INTERNALPAINT - ); + unsafe { + winuser::RedrawWindow( + self.modal_redraw_window, + ptr::null(), + ptr::null_mut(), + winuser::RDW_INTERNALPAINT + ); + } } // If new event processing has to be done (i.e. call NewEvents or defer), do it. If we're @@ -419,7 +434,7 @@ impl EventLoopRunner { self.call_event_handler(event); } - unsafe fn events_cleared(&mut self) { + fn events_cleared(&mut self) { match self.runner_state { // If we were handling events, send the EventsCleared message. RunnerState::HandlingEvents => { @@ -462,20 +477,18 @@ impl EventLoopRunner { } } - unsafe fn call_event_handler(&mut self, event: Event) { + fn call_event_handler(&mut self, event: Event) { match event { - Event::NewEvents(_) => (*self.event_loop).trigger_newevents_on_redraw.store(true, Ordering::Relaxed), - Event::EventsCleared => (*self.event_loop).trigger_newevents_on_redraw.store(false, Ordering::Relaxed), + Event::NewEvents(_) => self.trigger_newevents_on_redraw.store(true, Ordering::Relaxed), + Event::EventsCleared => self.trigger_newevents_on_redraw.store(false, Ordering::Relaxed), _ => () } - assert_eq!(mem::size_of::>(), mem::size_of::>()); - let event_loop_ref = &*(self.event_loop as *const RootEventLoop); if self.control_flow != ControlFlow::Exit { - (*self.event_handler)(event, event_loop_ref, &mut self.control_flow); + (*self.event_handler)(event, &mut self.control_flow); } else { - (*self.event_handler)(event, event_loop_ref, &mut ControlFlow::Exit); + (*self.event_handler)(event, &mut ControlFlow::Exit); } } } @@ -699,7 +712,7 @@ fn thread_event_target_window(event_loop_runner: EventLoopRunnerShared) -> (winuser::WS_VISIBLE | winuser::WS_POPUP) as _ ); - let (tx, rx) = crossbeam_channel::unbounded(); + let (tx, rx) = mpsc::channel(); let subclass_input = ThreadMsgTargetSubclassInput { event_loop_runner, diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 8140cc19ee..ee40fcfd1d 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -68,7 +68,7 @@ unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> B } impl Window { - pub fn new( + pub fn new( event_loop: &EventLoop, w_attr: WindowAttributes, pl_attr: PlatformSpecificWindowBuilderAttributes, @@ -91,7 +91,11 @@ impl Window { panic!("OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`"); } - let file_drop_handler = FileDropHandler::new(win.window.0/*, event_loop.event_send.clone()*/); + let file_drop_runner = event_loop.runner_shared.clone(); + let file_drop_handler = FileDropHandler::new( + win.window.0, + Box::new(move |event| if let Ok(e) = event.map_nonuser_event() {file_drop_runner.send_event(e)}) + ); let handler_interface_ptr = &mut (*file_drop_handler.data).interface as LPDROPTARGET; assert_eq!(ole2::RegisterDragDrop(win.window.0, handler_interface_ptr), S_OK); @@ -849,7 +853,7 @@ pub unsafe fn adjust_size( (rect.right - rect.left, rect.bottom - rect.top) } -unsafe fn init( +unsafe fn init( mut attributes: WindowAttributes, mut pl_attribs: PlatformSpecificWindowBuilderAttributes, event_loop: &event_loop::EventLoop, diff --git a/src/window.rs b/src/window.rs index eeed57aa36..05fe6a5523 100644 --- a/src/window.rs +++ b/src/window.rs @@ -283,7 +283,7 @@ impl WindowBuilder { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn build(mut self, event_loop: &EventLoop) -> Result { + pub fn build(mut self, event_loop: &EventLoop) -> Result { self.window.dimensions = Some(self.window.dimensions.unwrap_or_else(|| { if let Some(ref monitor) = self.window.fullscreen { // resizing the window to the dimensions of the monitor when fullscreen @@ -311,7 +311,7 @@ impl Window { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn new(event_loop: &EventLoop) -> Result { + pub fn new(event_loop: &EventLoop) -> Result { let builder = WindowBuilder::new(); builder.build(event_loop) } From 5289d22372046bac403a279c3641737c0cfc46d2 Mon Sep 17 00:00:00 2001 From: Osspial Date: Fri, 9 Nov 2018 00:00:27 -0500 Subject: [PATCH 29/40] Remove serde implementations from ControlFlow --- CHANGELOG.md | 1 + src/event_loop.rs | 1 - tests/serde_objects.rs | 7 +++---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07a1f7834c..62e2f8bb79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - Can be used to perform logic that depends on all events being processed (e.g. an iteration of a game loop). - `LoopDestroyed` is emitted when the `run` or `run_return` method is about to exit. - Rename `MonitorId` to `MonitorHandle`. +- Removed `serde` implementations from `ControlFlow`. # Version 0.18.0 (2018-11-07) diff --git a/src/event_loop.rs b/src/event_loop.rs index efd14aea62..b23c4a39bd 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -53,7 +53,6 @@ impl std::fmt::Debug for EventLoop { /// /// [events_cleared]: ../event/enum.Event.html#variant.EventsCleared #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ControlFlow { /// When the current loop iteration finishes, immediately begin a new iteration regardless of /// whether or not new events are available to process. diff --git a/tests/serde_objects.rs b/tests/serde_objects.rs index b5a49631b6..5effbbda09 100644 --- a/tests/serde_objects.rs +++ b/tests/serde_objects.rs @@ -3,8 +3,8 @@ extern crate serde; extern crate winit; -use winit::{ControlFlow, MouseCursor}; -use winit::{ +use winit::window::{MouseCursor}; +use winit::event::{ KeyboardInput, TouchPhase, ElementState, MouseButton, MouseScrollDelta, VirtualKeyCode, ModifiersState }; @@ -14,8 +14,7 @@ use serde::{Serialize, Deserialize}; fn needs_serde>() {} #[test] -fn root_serde() { - needs_serde::(); +fn window_serde() { needs_serde::(); } From d9c3daca9b459e02ef614568fe803a723965fe8d Mon Sep 17 00:00:00 2001 From: Osspial Date: Fri, 9 Nov 2018 20:41:15 -0500 Subject: [PATCH 30/40] Fix 1.24.1 build --- src/event_loop.rs | 8 ++++---- src/platform_impl/windows/window.rs | 2 +- src/window.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/event_loop.rs b/src/event_loop.rs index b23c4a39bd..c2af368905 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -34,8 +34,8 @@ pub struct EventLoop { pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync } -impl std::fmt::Debug for EventLoop { - fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Debug for EventLoop { + fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { fmtr.pad("EventLoop { .. }") } } @@ -154,8 +154,8 @@ impl EventLoopProxy { } } -impl std::fmt::Debug for EventLoopProxy { - fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Debug for EventLoopProxy { + fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { fmtr.pad("EventLoopProxy { .. }") } } diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index ee40fcfd1d..78bc5e14ea 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -614,7 +614,7 @@ impl Window { let mut window_state_lock = self.window_state.lock(); unsafe { let monitor_rect = monitor.as_ref() - .map(|RootMonitorHandle{ ref inner }| { + .map(|&RootMonitorHandle{ ref inner }| { let (x, y): (i32, i32) = inner.get_position().into(); let (width, height): (u32, u32) = inner.get_dimensions().into(); (x, y, width, height) diff --git a/src/window.rs b/src/window.rs index 05fe6a5523..a689199801 100644 --- a/src/window.rs +++ b/src/window.rs @@ -33,8 +33,8 @@ pub struct Window { pub(crate) window: platform_impl::Window, } -impl std::fmt::Debug for Window { - fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Debug for Window { + fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { fmtr.pad("Window { .. }") } } @@ -58,8 +58,8 @@ pub struct WindowBuilder { pub(crate) platform_specific: platform_impl::PlatformSpecificWindowBuilderAttributes, } -impl std::fmt::Debug for WindowBuilder { - fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Debug for WindowBuilder { + fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { fmtr.debug_struct("WindowBuilder") .field("window", &self.window) .finish() From 9f36a7a68e1dc379cf9091213dae2c3586d3e473 Mon Sep 17 00:00:00 2001 From: Osspial Date: Wed, 14 Nov 2018 21:28:38 -0500 Subject: [PATCH 31/40] Fix freeze when setting decorations --- src/platform_impl/windows/window.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 78bc5e14ea..3c8c46fdff 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -725,6 +725,7 @@ impl Window { let window = self.window.clone(); + drop(window_state); self.thread_executor.execute_in_thread(move || { winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style); winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style); From fa46825a289ca0587dc97f9c00dea5516fb4925a Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 15 Nov 2018 16:40:48 -0500 Subject: [PATCH 32/40] Replace &EventLoop in callback with &EventLoopWindowTarget --- src/event_loop.rs | 15 +++++++- src/platform/desktop.rs | 6 ++-- src/platform_impl/windows/event_loop.rs | 48 +++++++++++++++---------- src/platform_impl/windows/mod.rs | 2 +- src/platform_impl/windows/window.rs | 6 ++-- src/window.rs | 8 ++--- 6 files changed, 55 insertions(+), 30 deletions(-) diff --git a/src/event_loop.rs b/src/event_loop.rs index c2af368905..174d300891 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -11,6 +11,7 @@ //! [send_event]: ./struct.EventLoopProxy.html#method.send_event use std::{fmt, error}; use std::time::Instant; +use std::ops::Deref; use platform_impl; use event::Event; @@ -34,6 +35,11 @@ pub struct EventLoop { pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync } +pub struct EventLoopWindowTarget { + pub(crate) p: platform_impl::EventLoopWindowTarget, + pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync +} + impl fmt::Debug for EventLoop { fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { fmtr.pad("EventLoop { .. }") @@ -123,7 +129,7 @@ impl EventLoop { /// [`ControlFlow`]: ./enum.ControlFlow.html #[inline] pub fn run(self, event_handler: F) -> ! - where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow) + where F: 'static + FnMut(Event, &EventLoopWindowTarget, &mut ControlFlow) { self.event_loop.run(event_handler) } @@ -137,6 +143,13 @@ impl EventLoop { } } +impl Deref for EventLoop { + type Target = EventLoopWindowTarget; + fn deref(&self) -> &EventLoopWindowTarget { + self.event_loop.window_target() + } +} + /// Used to send custom events to `EventLoop`. #[derive(Clone)] pub struct EventLoopProxy { diff --git a/src/platform/desktop.rs b/src/platform/desktop.rs index 5f32460b2f..0f9f9fe07e 100644 --- a/src/platform/desktop.rs +++ b/src/platform/desktop.rs @@ -5,7 +5,7 @@ ))] use event::Event; -use event_loop::{EventLoop, ControlFlow}; +use event_loop::{EventLoop, EventLoopWindowTarget, ControlFlow}; /// Additional methods on `EventLoop` that are specific to desktop platforms. pub trait EventLoopExtDesktop { @@ -17,14 +17,14 @@ pub trait EventLoopExtDesktop { /// Unlikes `run`, this function accepts non-`'static` (i.e. non-`move`) closures and returns /// control flow to the caller when `control_flow` is set to `ControlFlow::Exit`. fn run_return(&mut self, event_handler: F) - where F: FnMut(Event, &EventLoop, &mut ControlFlow); + where F: FnMut(Event, &EventLoopWindowTarget, &mut ControlFlow); } impl EventLoopExtDesktop for EventLoop { type UserEvent = T; fn run_return(&mut self, event_handler: F) - where F: FnMut(Event, &EventLoop, &mut ControlFlow) + where F: FnMut(Event, &EventLoopWindowTarget, &mut ControlFlow) { self.event_loop.run_return(event_handler) } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 19fe8346d7..aa3c1f052a 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -22,6 +22,7 @@ use std::time::{Duration, Instant}; use std::rc::Rc; use std::cell::RefCell; use std::collections::VecDeque; +use std::marker::PhantomData; use parking_lot::Mutex; use winapi::ctypes::c_int; @@ -43,7 +44,7 @@ use winapi::um::winnt::{LONG, LPCSTR, SHORT}; use window::WindowId as RootWindowId; use monitor::MonitorHandle; -use event_loop::{ControlFlow, EventLoop as RootEventLoop, EventLoopClosed}; +use event_loop::{ControlFlow, EventLoopWindowTarget as RootELW, EventLoopClosed}; use dpi::{LogicalPosition, LogicalSize, PhysicalSize}; use event::{DeviceEvent, Touch, TouchPhase, StartCause, KeyboardInput, Event, WindowEvent}; use platform_impl::platform::{event, Cursor, WindowId, DEVICE_ID, wrap_device_id, util}; @@ -138,11 +139,15 @@ impl ThreadMsgTargetSubclassInput { } } -pub struct EventLoop { +pub struct EventLoop { // Id of the background thread from the Win32 API. - thread_id: DWORD, thread_msg_target: HWND, thread_msg_sender: Sender, + window_target: RootELW +} + +pub struct EventLoopWindowTarget { + thread_id: DWORD, trigger_newevents_on_redraw: Arc, pub(crate) runner_shared: EventLoopRunnerShared, } @@ -152,6 +157,10 @@ impl EventLoop { Self::with_dpi_awareness(true) } + pub fn window_target(&self) -> &RootELW { + &self.window_target + } + pub fn with_dpi_awareness(dpi_aware: bool) -> EventLoop { become_dpi_aware(dpi_aware); @@ -163,37 +172,40 @@ impl EventLoop { let (thread_msg_target, thread_msg_sender) = thread_event_target_window(runner_shared.clone()); EventLoop { - thread_id, thread_msg_target, thread_msg_sender, - trigger_newevents_on_redraw: Arc::new(AtomicBool::new(true)), - runner_shared + window_target: RootELW { + p: EventLoopWindowTarget { + thread_id, + trigger_newevents_on_redraw: Arc::new(AtomicBool::new(true)), + runner_shared + }, + _marker: PhantomData + } } } pub fn run(mut self, event_handler: F) -> ! - where F: 'static + FnMut(Event, &RootEventLoop, &mut ControlFlow) + where F: 'static + FnMut(Event, &RootELW, &mut ControlFlow) { self.run_return(event_handler); ::std::process::exit(0); } pub fn run_return(&mut self, mut event_handler: F) - where F: FnMut(Event, &RootEventLoop, &mut ControlFlow) + where F: FnMut(Event, &RootELW, &mut ControlFlow) { unsafe{ winuser::IsGUIThread(1); } - assert_eq!(mem::size_of::>(), mem::size_of::>()); - let self_ptr = self as *const EventLoop; + let event_loop_windows_ref = &self.window_target; let mut runner = unsafe{ EventLoopRunner::new( self, move |event, control_flow| { - let event_loop_ref = &*(self_ptr as *const RootEventLoop); - event_handler(event, event_loop_ref, control_flow) + event_handler(event, event_loop_windows_ref, control_flow) } ) }; { - let runner_shared = self.runner_shared.clone(); + let runner_shared = self.window_target.p.runner_shared.clone(); let mut runner_ref = runner_shared.runner.borrow_mut(); loop { let event = runner_shared.buffer.borrow_mut().pop_front(); @@ -206,7 +218,7 @@ impl EventLoop { } macro_rules! runner { - () => {{ self.runner_shared.runner.borrow_mut().as_mut().unwrap() }}; + () => {{ self.window_target.p.runner_shared.runner.borrow_mut().as_mut().unwrap() }}; } unsafe { @@ -244,7 +256,7 @@ impl EventLoop { } runner!().call_event_handler(Event::LoopDestroyed); - *self.runner_shared.runner.borrow_mut() = None; + *self.window_target.p.runner_shared.runner.borrow_mut() = None; } pub fn create_proxy(&self) -> EventLoopProxy { @@ -253,7 +265,9 @@ impl EventLoop { event_send: self.thread_msg_sender.clone() } } +} +impl EventLoopWindowTarget { #[inline(always)] pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor { EventLoopThreadExecutor { @@ -309,7 +323,7 @@ impl EventLoopRunner { where F: FnMut(Event, &mut ControlFlow) { EventLoopRunner { - trigger_newevents_on_redraw: event_loop.trigger_newevents_on_redraw.clone(), + trigger_newevents_on_redraw: event_loop.window_target.p.trigger_newevents_on_redraw.clone(), control_flow: ControlFlow::default(), runner_state: RunnerState::New, in_modal_loop: false, @@ -545,8 +559,6 @@ impl Drop for EventLoop { fn drop(&mut self) { unsafe { winuser::DestroyWindow(self.thread_msg_target); - // Posting `WM_QUIT` will cause `GetMessage` to stop. - winuser::PostThreadMessageA(self.thread_id, winuser::WM_QUIT, 0, 0); } } } diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 5e989bf0b0..b088201b00 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -3,7 +3,7 @@ use winapi; use winapi::shared::windef::HWND; -pub use self::event_loop::{EventLoop, EventLoopProxy}; +pub use self::event_loop::{EventLoop, EventLoopWindowTarget, EventLoopProxy}; pub use self::monitor::MonitorHandle; pub use self::window::Window; diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 3c8c46fdff..0eaf5730e3 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -23,7 +23,7 @@ use dpi::{LogicalPosition, LogicalSize, PhysicalSize}; use monitor::MonitorHandle as RootMonitorHandle; use platform_impl::platform::{Cursor, PlatformSpecificWindowBuilderAttributes, WindowId}; use platform_impl::platform::dpi::{dpi_to_scale_factor, get_hwnd_dpi}; -use platform_impl::platform::event_loop::{self, EventLoop, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}; +use platform_impl::platform::event_loop::{self, EventLoopWindowTarget, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID, REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID}; use platform_impl::platform::event_loop::WindowState; use platform_impl::platform::icon::{self, IconType, WinIcon}; use platform_impl::platform::monitor; @@ -69,7 +69,7 @@ unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> B impl Window { pub fn new( - event_loop: &EventLoop, + event_loop: &EventLoopWindowTarget, w_attr: WindowAttributes, pl_attr: PlatformSpecificWindowBuilderAttributes, ) -> Result { @@ -857,7 +857,7 @@ pub unsafe fn adjust_size( unsafe fn init( mut attributes: WindowAttributes, mut pl_attribs: PlatformSpecificWindowBuilderAttributes, - event_loop: &event_loop::EventLoop, + event_loop: &EventLoopWindowTarget, ) -> Result { let title = OsStr::new(&attributes.title) .encode_wide() diff --git a/src/window.rs b/src/window.rs index a689199801..871eef351c 100644 --- a/src/window.rs +++ b/src/window.rs @@ -2,7 +2,7 @@ use std::{fmt, error}; use platform_impl; -use event_loop::EventLoop; +use event_loop::EventLoopWindowTarget; use monitor::{AvailableMonitorsIter, MonitorHandle}; use dpi::{LogicalPosition, LogicalSize}; @@ -283,7 +283,7 @@ impl WindowBuilder { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn build(mut self, event_loop: &EventLoop) -> Result { + pub fn build(mut self, window_target: &EventLoopWindowTarget) -> Result { self.window.dimensions = Some(self.window.dimensions.unwrap_or_else(|| { if let Some(ref monitor) = self.window.fullscreen { // resizing the window to the dimensions of the monitor when fullscreen @@ -296,7 +296,7 @@ impl WindowBuilder { // building platform_impl::Window::new( - &event_loop.event_loop, + &window_target.p, self.window, self.platform_specific, ).map(|window| Window { window }) @@ -311,7 +311,7 @@ impl Window { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. #[inline] - pub fn new(event_loop: &EventLoop) -> Result { + pub fn new(event_loop: &EventLoopWindowTarget) -> Result { let builder = WindowBuilder::new(); builder.build(event_loop) } From 2a3cefd8c5df1c06127b05651cbdf5e3d9e3a6d3 Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 15 Nov 2018 16:45:17 -0500 Subject: [PATCH 33/40] Document and implement Debug for EventLoopWindowTarget --- src/event_loop.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/event_loop.rs b/src/event_loop.rs index 174d300891..ca217f7c97 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -35,6 +35,11 @@ pub struct EventLoop { pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync } +/// Target that associates windows with an `EventLoop`. +/// +/// This type exists to allow you to create new windows while Winit executes your callback. +/// `EventLoop` will coerce into this type, so functions that take this as a parameter can also +/// take `&EventLoop`. pub struct EventLoopWindowTarget { pub(crate) p: platform_impl::EventLoopWindowTarget, pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync @@ -46,6 +51,12 @@ impl fmt::Debug for EventLoop { } } +impl fmt::Debug for EventLoopWindowTarget { + fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { + fmtr.pad("EventLoopWindowTarget { .. }") + } +} + /// Set by the user callback given to the `EventLoop::run` method. /// /// Indicates the desired behavior of the event loop after [`Event::EventsCleared`][events_cleared] From 5a3a5e2293cec3e566c4aac344ae7eaa343608b5 Mon Sep 17 00:00:00 2001 From: Osspial Date: Thu, 15 Nov 2018 22:43:59 -0500 Subject: [PATCH 34/40] Fix some deadlocks that could occur when changing window state --- src/platform_impl/windows/window.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 0eaf5730e3..a5b73caab1 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -425,6 +425,7 @@ impl Window { if currently_grabbed == grab && grab == window_state_lock.cursor_grabbed { return Ok(()); } + drop(window_state_lock); let window = self.window.clone(); let window_state = Arc::clone(&self.window_state); let (tx, rx) = channel(); @@ -435,7 +436,6 @@ impl Window { } let _ = tx.send(result); }); - drop(window_state_lock); rx.recv().unwrap() } @@ -500,6 +500,7 @@ impl Window { // We only maximize if we're not in fullscreen. if window_state.fullscreen.is_none() { let window = self.window.clone(); + drop(window_state); unsafe { // `ShowWindow` resizes the window, so it must be called from the main thread. self.thread_executor.execute_in_thread(move || { @@ -754,6 +755,7 @@ impl Window { let mut window_state = self.window_state.lock(); if mem::replace(&mut window_state.always_on_top, always_on_top) != always_on_top { let window = self.window.clone(); + drop(window_state); self.thread_executor.execute_in_thread(move || { let insert_after = if always_on_top { winuser::HWND_TOPMOST From 2c18b804df66f49f93cfe722a679d6c5e01d8cb1 Mon Sep 17 00:00:00 2001 From: Osspial Date: Sun, 18 Nov 2018 18:51:24 -0500 Subject: [PATCH 35/40] Fix thread executor not executing closure when called from non-loop thread --- src/platform_impl/windows/event_loop.rs | 31 ++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index aa3c1f052a..6c7090d7ca 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -140,8 +140,6 @@ impl ThreadMsgTargetSubclassInput { } pub struct EventLoop { - // Id of the background thread from the Win32 API. - thread_msg_target: HWND, thread_msg_sender: Sender, window_target: RootELW } @@ -149,6 +147,7 @@ pub struct EventLoop { pub struct EventLoopWindowTarget { thread_id: DWORD, trigger_newevents_on_redraw: Arc, + thread_msg_target: HWND, pub(crate) runner_shared: EventLoopRunnerShared, } @@ -172,11 +171,12 @@ impl EventLoop { let (thread_msg_target, thread_msg_sender) = thread_event_target_window(runner_shared.clone()); EventLoop { - thread_msg_target, thread_msg_sender, + thread_msg_sender, window_target: RootELW { p: EventLoopWindowTarget { thread_id, trigger_newevents_on_redraw: Arc::new(AtomicBool::new(true)), + thread_msg_target, runner_shared }, _marker: PhantomData @@ -261,7 +261,7 @@ impl EventLoop { pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { - target_window: self.thread_msg_target, + target_window: self.window_target.p.thread_msg_target, event_send: self.thread_msg_sender.clone() } } @@ -272,7 +272,8 @@ impl EventLoopWindowTarget { pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor { EventLoopThreadExecutor { thread_id: self.thread_id, - trigger_newevents_on_redraw: self.trigger_newevents_on_redraw.clone() + trigger_newevents_on_redraw: self.trigger_newevents_on_redraw.clone(), + target_window: self.thread_msg_target } } } @@ -327,7 +328,7 @@ impl EventLoopRunner { control_flow: ControlFlow::default(), runner_state: RunnerState::New, in_modal_loop: false, - modal_redraw_window: event_loop.thread_msg_target, + modal_redraw_window: event_loop.window_target.p.thread_msg_target, event_handler: mem::transmute::< Box, &mut ControlFlow)>, Box, &mut ControlFlow)> @@ -558,16 +559,20 @@ fn dur2timeout(dur: Duration) -> DWORD { impl Drop for EventLoop { fn drop(&mut self) { unsafe { - winuser::DestroyWindow(self.thread_msg_target); + winuser::DestroyWindow(self.window_target.p.thread_msg_target); } } } pub(crate) struct EventLoopThreadExecutor { thread_id: DWORD, - trigger_newevents_on_redraw: Arc + trigger_newevents_on_redraw: Arc, + target_window: HWND } +unsafe impl Send for EventLoopThreadExecutor {} +unsafe impl Sync for EventLoopThreadExecutor {} + impl EventLoopThreadExecutor { /// Check to see if we're in the parent event loop's thread. pub(super) fn in_event_loop_thread(&self) -> bool { @@ -605,11 +610,11 @@ impl EventLoopThreadExecutor { let raw = Box::into_raw(boxed2); - let res = winuser::PostThreadMessageA(self.thread_id, *EXEC_MSG_ID, - raw as *mut () as usize as WPARAM, 0); - // PostThreadMessage can only fail if the thread ID is invalid (which shouldn't happen - // as the events loop is still alive) or if the queue is full. - assert!(res != 0, "PostThreadMessage failed ; is the messages queue full?"); + let res = winuser::PostMessageW( + self.target_window, *EXEC_MSG_ID, + raw as *mut () as usize as WPARAM, 0 + ); + assert!(res != 0, "PostMessage failed ; is the messages queue full?"); } } } From 54ce6a21a0722e408ae49c74f5008005fc1e4cbf Mon Sep 17 00:00:00 2001 From: Osspial Date: Sun, 18 Nov 2018 19:12:45 -0500 Subject: [PATCH 36/40] Fix buffered events not getting dispatched --- src/platform_impl/windows/event_loop.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 6c7090d7ca..c7f989d515 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -297,9 +297,26 @@ impl ELRShared { if let Ok(mut runner_ref) = self.runner.try_borrow_mut() { if let Some(ref mut runner) = *runner_ref { runner.process_event(event); + + // Dispatch any events that were buffered during the call to `process_event`. + loop { + // We do this instead of using a `while let` loop because if we use a `while let` + // loop the reference returned `borrow_mut()` doesn't get dropped until the end + // of the loop's body and attempts to add events to the event buffer while in + // `process_event` will fail. + let buffered_event_opt = self.buffer.borrow_mut().pop_front(); + match buffered_event_opt { + Some(event) => runner.process_event(event), + None => break + } + } + return; } } + + // If the runner is already borrowed, we're in the middle of an event loop invocation. Add + // the event to a buffer to be processed later. self.buffer.borrow_mut().push_back(event) } } From 8269ed2a9270e5ec5b14f80fd21d1e0e6f51be29 Mon Sep 17 00:00:00 2001 From: Osspial Date: Mon, 19 Nov 2018 23:51:20 -0500 Subject: [PATCH 37/40] Fix crash with runner refcell not getting dropped --- src/platform_impl/windows/event_loop.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index c7f989d515..f93fc485d1 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -239,7 +239,8 @@ impl EventLoop { } runner!().events_cleared(); - match runner!().control_flow { + let control_flow = runner!().control_flow; + match control_flow { ControlFlow::Exit => break 'main, ControlFlow::Wait => { if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { From 48a2526c92ce4fc27c3be260cd8c1d2eecb2a149 Mon Sep 17 00:00:00 2001 From: Osspial Date: Fri, 21 Dec 2018 13:11:16 -0500 Subject: [PATCH 38/40] Address review feedback --- src/platform/desktop.rs | 2 +- src/platform_impl/windows/event_loop.rs | 81 ++++++++++++------------- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/platform/desktop.rs b/src/platform/desktop.rs index 0f9f9fe07e..057838903e 100644 --- a/src/platform/desktop.rs +++ b/src/platform/desktop.rs @@ -14,7 +14,7 @@ pub trait EventLoopExtDesktop { /// Initializes the `winit` event loop. /// - /// Unlikes `run`, this function accepts non-`'static` (i.e. non-`move`) closures and returns + /// Unlike `run`, this function accepts non-`'static` (i.e. non-`move`) closures and returns /// control flow to the caller when `control_flow` is set to `ControlFlow::Exit`. fn run_return(&mut self, event_handler: F) where F: FnMut(Event, &EventLoopWindowTarget, &mut ControlFlow); diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index f93fc485d1..85ac1510f3 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -130,7 +130,7 @@ impl SubclassInput { struct ThreadMsgTargetSubclassInput { event_loop_runner: EventLoopRunnerShared, - user_event_receiver: Receiver + user_event_receiver: Receiver, } impl ThreadMsgTargetSubclassInput { @@ -141,7 +141,7 @@ impl ThreadMsgTargetSubclassInput { pub struct EventLoop { thread_msg_sender: Sender, - window_target: RootELW + window_target: RootELW, } pub struct EventLoopWindowTarget { @@ -166,7 +166,7 @@ impl EventLoop { let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; let runner_shared = Rc::new(ELRShared { runner: RefCell::new(None), - buffer: RefCell::new(VecDeque::new()) + buffer: RefCell::new(VecDeque::new()), }); let (thread_msg_target, thread_msg_sender) = thread_event_target_window(runner_shared.clone()); @@ -177,10 +177,10 @@ impl EventLoop { thread_id, trigger_newevents_on_redraw: Arc::new(AtomicBool::new(true)), thread_msg_target, - runner_shared + runner_shared, }, - _marker: PhantomData - } + _marker: PhantomData, + }, } } @@ -263,7 +263,7 @@ impl EventLoop { pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { target_window: self.window_target.p.thread_msg_target, - event_send: self.thread_msg_sender.clone() + event_send: self.thread_msg_sender.clone(), } } } @@ -274,7 +274,7 @@ impl EventLoopWindowTarget { EventLoopThreadExecutor { thread_id: self.thread_id, trigger_newevents_on_redraw: self.trigger_newevents_on_redraw.clone(), - target_window: self.thread_msg_target + target_window: self.thread_msg_target, } } } @@ -282,7 +282,7 @@ impl EventLoopWindowTarget { pub(crate) type EventLoopRunnerShared = Rc>; pub(crate) struct ELRShared { runner: RefCell>>, - buffer: RefCell>> + buffer: RefCell>>, } pub(crate) struct EventLoopRunner { trigger_newevents_on_redraw: Arc, @@ -290,7 +290,7 @@ pub(crate) struct EventLoopRunner { runner_state: RunnerState, modal_redraw_window: HWND, in_modal_loop: bool, - event_handler: Box, &mut ControlFlow)> + event_handler: Box, &mut ControlFlow)>, } impl ELRShared { @@ -385,7 +385,7 @@ impl EventLoopRunner { true => { self.call_event_handler(Event::NewEvents(StartCause::ResumeTimeReached { start: wait_start, - requested_resume: resume_time + requested_resume: resume_time, })); RunnerState::HandlingEvents }, @@ -434,7 +434,7 @@ impl EventLoopRunner { self.call_event_handler( Event::NewEvents(StartCause::WaitCancelled { start: wait_start, - requested_resume: None + requested_resume: None, }) ) }, @@ -444,12 +444,12 @@ impl EventLoopRunner { // has been reached. true => StartCause::ResumeTimeReached { start: wait_start, - requested_resume: resume_time + requested_resume: resume_time, }, // Otherwise, the requested resume time HASN'T been reached and we send a WaitCancelled. false => StartCause::WaitCancelled { start: wait_start, - requested_resume: Some(resume_time) + requested_resume: Some(resume_time), }, }; self.call_event_handler(Event::NewEvents(start_cause)); @@ -494,7 +494,7 @@ impl EventLoopRunner { if Instant::now() >= resume_time { self.call_event_handler(Event::NewEvents(StartCause::ResumeTimeReached { start: wait_start, - requested_resume: resume_time + requested_resume: resume_time, })); self.call_event_handler(Event::EventsCleared); } @@ -585,7 +585,7 @@ impl Drop for EventLoop { pub(crate) struct EventLoopThreadExecutor { thread_id: DWORD, trigger_newevents_on_redraw: Arc, - target_window: HWND + target_window: HWND, } unsafe impl Send for EventLoopThreadExecutor {} @@ -641,7 +641,7 @@ impl EventLoopThreadExecutor { #[derive(Clone)] pub struct EventLoopProxy { target_window: HWND, - event_send: Sender + event_send: Sender, } unsafe impl Send for EventLoopProxy {} @@ -751,7 +751,7 @@ fn thread_event_target_window(event_loop_runner: EventLoopRunnerShared) -> let subclass_input = ThreadMsgTargetSubclassInput { event_loop_runner, - user_event_receiver: rx + user_event_receiver: rx, }; let input_ptr = Box::into_raw(Box::new(subclass_input)); let subclass_result = commctrl::SetWindowSubclass( @@ -836,7 +836,7 @@ unsafe extern "system" fn public_window_callback( use event::WindowEvent::CloseRequested; subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: CloseRequested + event: CloseRequested, }); 0 }, @@ -846,7 +846,7 @@ unsafe extern "system" fn public_window_callback( ole2::RevokeDragDrop(window); subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: Destroyed + event: Destroyed, }); Box::from_raw(subclass_input); @@ -1004,7 +1004,7 @@ unsafe extern "system" fn public_window_callback( if mouse_in_window { subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: CursorLeft { device_id: DEVICE_ID } + event: CursorLeft { device_id: DEVICE_ID }, }); } @@ -1043,8 +1043,8 @@ unsafe extern "system" fn public_window_callback( scancode: scancode, virtual_keycode: vkey, modifiers: event::get_key_mods(), - } - } + }, + }, }); // Windows doesn't emit a delete character by default, but in order to make it // consistent with the other platforms we'll emit a delete character here. @@ -1072,7 +1072,7 @@ unsafe extern "system" fn public_window_callback( virtual_keycode: vkey, modifiers: event::get_key_mods(), }, - } + }, }); } 0 @@ -1087,7 +1087,7 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() } + event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() }, }); 0 }, @@ -1101,7 +1101,7 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() } + event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() }, }); 0 }, @@ -1115,7 +1115,7 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() } + event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() }, }); 0 }, @@ -1129,7 +1129,7 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() } + event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() }, }); 0 }, @@ -1143,7 +1143,7 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() } + event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() }, }); 0 }, @@ -1157,7 +1157,7 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() } + event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() }, }); 0 }, @@ -1172,7 +1172,7 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() } + event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() }, }); 0 }, @@ -1187,7 +1187,7 @@ unsafe extern "system" fn public_window_callback( subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() } + event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() }, }); 0 }, @@ -1205,7 +1205,6 @@ unsafe extern "system" fn public_window_callback( }); 0 - // commctrl::DefSubclassProc(window, msg, wparam, lparam) }, winuser::WM_INPUT => { @@ -1226,21 +1225,21 @@ unsafe extern "system" fn public_window_callback( if x != 0.0 { subclass_input.send_event(Event::DeviceEvent { device_id, - event: Motion { axis: 0, value: x } + event: Motion { axis: 0, value: x }, }); } if y != 0.0 { subclass_input.send_event(Event::DeviceEvent { device_id, - event: Motion { axis: 1, value: y } + event: Motion { axis: 1, value: y }, }); } if x != 0.0 || y != 0.0 { subclass_input.send_event(Event::DeviceEvent { device_id, - event: MouseMotion { delta: (x, y) } + event: MouseMotion { delta: (x, y) }, }); } } @@ -1249,7 +1248,7 @@ unsafe extern "system" fn public_window_callback( let delta = mouse.usButtonData as SHORT / winuser::WHEEL_DELTA; subclass_input.send_event(Event::DeviceEvent { device_id, - event: MouseWheel { delta: LineDelta(0.0, delta as f32) } + event: MouseWheel { delta: LineDelta(0.0, delta as f32) }, }); } @@ -1266,7 +1265,7 @@ unsafe extern "system" fn public_window_callback( event: Button { button, state, - } + }, }); } } @@ -1344,7 +1343,7 @@ unsafe extern "system" fn public_window_callback( location, id: input.dwID as u64, device_id: DEVICE_ID, - }) + }), }); } } @@ -1356,7 +1355,7 @@ unsafe extern "system" fn public_window_callback( use event::WindowEvent::{Focused, CursorMoved}; subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: Focused(true) + event: Focused(true), }); let x = windowsx::GET_X_LPARAM(lparam) as f64; @@ -1376,7 +1375,7 @@ unsafe extern "system" fn public_window_callback( use event::WindowEvent::Focused; subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), - event: Focused(false) + event: Focused(false), }); 0 }, From b92d04347425ce68ed34160a1c8f2fd0d99f99a3 Mon Sep 17 00:00:00 2001 From: Osspial Date: Tue, 1 Jan 2019 15:41:34 -0500 Subject: [PATCH 39/40] Fix CHANGELOG typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62e2f8bb79..83190be154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ - Takes a closure that implements `'static + FnMut(Event, &EventLoop, &mut ControlFlow)`. - `&EventLoop` is provided to allow new `Window`s to be created. - **Major:** `platform::desktop` module exposes `EventLoopExtDesktop` trait with `run_return` method. - - Behaves identically to `run`, but returns control flow to the calling context can take non-`'static` closures. + - Behaves identically to `run`, but returns control flow to the calling context and can take non-`'static` closures. - `EventLoop`'s `poll_events` and `run_forever` methods have been removed in favor of `run` and `run_return`. - Changes to events: - Remove `Event::Awakened` in favor of `Event::UserEvent(T)`. From 7cb081c967894a24f78537b4f675e42db97b3851 Mon Sep 17 00:00:00 2001 From: Osspial Date: Mon, 4 Feb 2019 18:44:03 -0500 Subject: [PATCH 40/40] Catch panics in user callback --- src/platform_impl/windows/event_loop.rs | 29 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index ce38d54233..9bc874b6fd 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -15,6 +15,7 @@ use winapi::shared::basetsd::DWORD_PTR; use winapi::shared::basetsd::UINT_PTR; use std::{mem, panic, ptr}; +use std::any::Any; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{self, Sender, Receiver}; @@ -161,7 +162,7 @@ impl EventLoop { } macro_rules! runner { - () => {{ self.window_target.p.runner_shared.runner.borrow_mut().as_mut().unwrap() }}; + () => { self.window_target.p.runner_shared.runner.borrow_mut().as_mut().unwrap() }; } unsafe { @@ -181,6 +182,9 @@ impl EventLoop { msg_unprocessed = false; } runner!().events_cleared(); + if let Some(payload) = runner!().panic_error.take() { + panic::resume_unwind(payload); + } let control_flow = runner!().control_flow; match control_flow { @@ -234,7 +238,9 @@ pub(crate) struct EventLoopRunner { modal_redraw_window: HWND, in_modal_loop: bool, event_handler: Box, &mut ControlFlow)>, + panic_error: Option, } +type PanicError = Box; impl ELRShared { pub(crate) unsafe fn send_event(&self, event: Event) { @@ -293,7 +299,8 @@ impl EventLoopRunner { event_handler: mem::transmute::< Box, &mut ControlFlow)>, Box, &mut ControlFlow)> - >(Box::new(f)) + >(Box::new(f)), + panic_error: None, } } @@ -461,10 +468,20 @@ impl EventLoopRunner { } - if self.control_flow != ControlFlow::Exit { - (*self.event_handler)(event, &mut self.control_flow); - } else { - (*self.event_handler)(event, &mut ControlFlow::Exit); + if self.panic_error.is_none() { + let EventLoopRunner { + ref mut panic_error, + ref mut event_handler, + ref mut control_flow, + .. + } = self; + *panic_error = panic::catch_unwind(panic::AssertUnwindSafe(|| { + if *control_flow != ControlFlow::Exit { + (*event_handler)(event, control_flow); + } else { + (*event_handler)(event, &mut ControlFlow::Exit); + } + })).err(); } } }