Skip to content

Commit

Permalink
Add EventLoopBuilder
Browse files Browse the repository at this point in the history
This commit adds an `EventLoopBuilder` struct to simplify event loop
customization and providing options to it upon creation. It also
deprecates the use of `EventLoop::with_user_event` in favor of the same
method on new builder, and replaces old platforms specific extension
traits with the new ones on the `EventLoopBuilder`.
  • Loading branch information
madsmtm authored Feb 16, 2022
1 parent 0e52672 commit f3f6f10
Show file tree
Hide file tree
Showing 19 changed files with 323 additions and 270 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ And please only add new entries to the top of this list, right below the `# Unre
- **Breaking:** Bump `ndk` version to 0.6, ndk-sys to `v0.3`, `ndk-glue` to `0.6`.
- Remove no longer needed `WINIT_LINK_COLORSYNC` environment variable.
- **Breaking:** Rename the `Exit` variant of `ControlFlow` to `ExitWithCode`, which holds a value to control the exit code after running. Add an `Exit` constant which aliases to `ExitWithCode(0)` instead to avoid major breakage. This shouldn't affect most existing programs.
- Add `EventLoopBuilder`, which allows you to create and tweak the settings of an event loop before creating it.
- Deprecated `EventLoop::with_user_event`; use `EventLoopBuilder::with_user_event` instead.
- **Breaking:** Replaced `EventLoopExtMacOS` with `EventLoopBuilderExtMacOS` (which also has renamed methods).
- **Breaking:** Replaced `EventLoopExtWindows` with `EventLoopBuilderExtWindows` (which also has renamed methods).
- **Breaking:** Replaced `EventLoopExtUnix` with `EventLoopBuilderExtUnix` (which also has renamed methods).

# 0.26.1 (2022-01-05)

Expand Down
4 changes: 2 additions & 2 deletions examples/custom_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ fn main() {
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
event_loop::{ControlFlow, EventLoopBuilder},
window::WindowBuilder,
};

Expand All @@ -13,7 +13,7 @@ fn main() {
}

SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::<CustomEvent>::with_user_event();
let event_loop = EventLoopBuilder::<CustomEvent>::with_user_event().build();

let _window = WindowBuilder::new()
.with_title("A fantastic window!")
Expand Down
94 changes: 63 additions & 31 deletions src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//! [event_loop_proxy]: crate::event_loop::EventLoopProxy
//! [send_event]: crate::event_loop::EventLoopProxy::send_event
use instant::Instant;
use std::marker::PhantomData;
use std::ops::Deref;
use std::{error, fmt};

Expand All @@ -31,7 +32,7 @@ use crate::{event::Event, monitor::MonitorHandle, platform_impl};
///
pub struct EventLoop<T: 'static> {
pub(crate) event_loop: platform_impl::EventLoop<T>,
pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
}

/// Target that associates windows with an `EventLoop`.
Expand All @@ -42,7 +43,62 @@ pub struct EventLoop<T: 'static> {
/// `&EventLoop`.
pub struct EventLoopWindowTarget<T: 'static> {
pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
}

/// Object that allows building the event loop.
///
/// This is used to make specifying options that affect the whole application
/// easier. But note that constructing multiple event loops is not supported.
#[derive(Debug, Clone, Default)]
pub struct EventLoopBuilder<T: 'static> {
pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
_p: PhantomData<T>,
}

impl EventLoopBuilder<()> {
/// Start building a new event loop.
#[inline]
pub fn new() -> Self {
Self::with_user_event()
}
}

impl<T> EventLoopBuilder<T> {
/// Start building a new event loop, with the given type as the user event
/// type.
#[inline]
pub fn with_user_event() -> Self {
Self {
platform_specific: Default::default(),
_p: PhantomData,
}
}

/// Builds a new event loop.
///
/// ***For cross-platform compatibility, the `EventLoop` must be created on the main thread.***
/// Attempting to create the event loop on a different thread will panic. This restriction isn't
/// strictly necessary on all platforms, but is imposed to eliminate any nasty surprises when
/// porting to platforms that require it. `EventLoopBuilderExt::any_thread` functions are exposed
/// in the relevant `platform` module if the target platform supports creating an event loop on
/// any thread.
///
/// 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.
///
/// ## Platform-specific
///
/// - **iOS:** Can only be called on the main thread.
#[inline]
pub fn build(&mut self) -> EventLoop<T> {
EventLoop {
event_loop: platform_impl::EventLoop::new(&self.platform_specific),
_marker: PhantomData,
}
}
}

impl<T> fmt::Debug for EventLoop<T> {
Expand Down Expand Up @@ -119,41 +175,17 @@ impl Default for ControlFlow {
}

impl EventLoop<()> {
/// Builds a new event loop with a `()` as the user event type.
///
/// ***For cross-platform compatibility, the `EventLoop` must be created on the main thread.***
/// Attempting to create the event loop on a different thread will panic. This restriction isn't
/// strictly necessary on all platforms, but is imposed to eliminate any nasty surprises when
/// porting to platforms that require it. `EventLoopExt::new_any_thread` functions are exposed
/// in the relevant `platform` module if the target platform supports creating an event loop on
/// any thread.
///
/// 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.
///
/// ## Platform-specific
///
/// - **iOS:** Can only be called on the main thread.
/// Alias for `EventLoopBuilder::new().build()`.
#[inline]
pub fn new() -> EventLoop<()> {
EventLoop::<()>::with_user_event()
EventLoopBuilder::new().build()
}
}

impl<T> EventLoop<T> {
/// Builds a new event loop.
///
/// All caveats documented in [`EventLoop::new`] apply to this function.
///
/// ## Platform-specific
///
/// - **iOS:** Can only be called on the main thread.
#[deprecated = "Use `EventLoopBuiler::<T>::with_user_event().build()` instead."]
pub fn with_user_event() -> EventLoop<T> {
EventLoop {
event_loop: platform_impl::EventLoop::new(),
_marker: ::std::marker::PhantomData,
}
EventLoopBuilder::<T>::with_user_event().build()
}

/// Hijacks the calling thread and initializes the winit event loop with the provided
Expand Down
76 changes: 51 additions & 25 deletions src/platform/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ use std::os::raw::c_void;

use crate::{
dpi::LogicalSize,
event_loop::{EventLoop, EventLoopWindowTarget},
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
monitor::MonitorHandle,
platform_impl::get_aux_state_mut,
window::{Window, WindowBuilder},
};

Expand Down Expand Up @@ -74,7 +73,7 @@ impl WindowExtMacOS for Window {
}

/// Corresponds to `NSApplicationActivationPolicy`.
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ActivationPolicy {
/// Corresponds to `NSApplicationActivationPolicyRegular`.
Regular,
Expand Down Expand Up @@ -179,36 +178,63 @@ impl WindowBuilderExtMacOS for WindowBuilder {
}
}

pub trait EventLoopExtMacOS {
/// Sets the activation policy for the application. It is set to
/// `NSApplicationActivationPolicyRegular` by default.
pub trait EventLoopBuilderExtMacOS {
/// Sets the activation policy for the application.
///
/// This function only takes effect if it's called before calling [`run`](crate::event_loop::EventLoop::run) or
/// [`run_return`](crate::platform::run_return::EventLoopExtRunReturn::run_return)
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);

/// Used to prevent a default menubar menu from getting created
/// It is set to [`ActivationPolicy::Regular`] by default.
///
/// # Example
///
/// Set the activation policy to "accessory".
///
/// ```
/// use winit::event_loop::EventLoopBuilder;
/// #[cfg(target_os = "macos")]
/// use winit::platform::macos::{EventLoopBuilderExtMacOS, ActivationPolicy};
///
/// let mut builder = EventLoopBuilder::new();
/// #[cfg(target_os = "macos")]
/// builder.with_activation_policy(ActivationPolicy::Accessory);
/// # if false { // We can't test this part
/// let event_loop = builder.build();
/// # }
/// ```
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self;

/// Used to control whether a default menubar menu is created.
///
/// Menu creation is enabled by default.
///
/// The default menu creation is enabled by default.
/// # Example
///
/// This function only takes effect if it's called before calling
/// [`run`](crate::event_loop::EventLoop::run) or
/// [`run_return`](crate::platform::run_return::EventLoopExtRunReturn::run_return)
fn enable_default_menu_creation(&mut self, enable: bool);
/// Disable creating a default menubar.
///
/// ```
/// use winit::event_loop::EventLoopBuilder;
/// #[cfg(target_os = "macos")]
/// use winit::platform::macos::EventLoopBuilderExtMacOS;
///
/// let mut builder = EventLoopBuilder::new();
/// #[cfg(target_os = "macos")]
/// builder.with_default_menu(false);
/// # if false { // We can't test this part
/// let event_loop = builder.build();
/// # }
/// ```
fn with_default_menu(&mut self, enable: bool) -> &mut Self;
}
impl<T> EventLoopExtMacOS for EventLoop<T> {

impl<T> EventLoopBuilderExtMacOS for EventLoopBuilder<T> {
#[inline]
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
unsafe {
get_aux_state_mut(&**self.event_loop.delegate).activation_policy = activation_policy;
}
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self {
self.platform_specific.activation_policy = activation_policy;
self
}

#[inline]
fn enable_default_menu_creation(&mut self, enable: bool) {
unsafe {
get_aux_state_mut(&**self.event_loop.delegate).create_default_menu = enable;
}
fn with_default_menu(&mut self, enable: bool) -> &mut Self {
self.platform_specific.default_menu = enable;
self
}
}

Expand Down
Loading

0 comments on commit f3f6f10

Please sign in to comment.