mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Add EventLoopBuilder
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`.
This commit is contained in:
parent
0e52672f4a
commit
f3f6f1008a
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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!")
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
@ -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`.
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
/// 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 prevent a default menubar menu from getting created
|
||||
/// Used to control whether a default menubar menu is created.
|
||||
///
|
||||
/// The default menu creation is enabled by default.
|
||||
/// Menu creation is enabled by default.
|
||||
///
|
||||
/// 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);
|
||||
/// # Example
|
||||
///
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::os::raw;
|
|||
use std::{ptr, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
event_loop::{EventLoop, EventLoopWindowTarget},
|
||||
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
|
||||
monitor::MonitorHandle,
|
||||
window::{Window, WindowBuilder},
|
||||
};
|
||||
|
@ -21,8 +21,7 @@ use crate::dpi::Size;
|
|||
#[cfg(feature = "x11")]
|
||||
use crate::platform_impl::x11::{ffi::XVisualInfo, XConnection};
|
||||
use crate::platform_impl::{
|
||||
EventLoop as LinuxEventLoop, EventLoopWindowTarget as LinuxEventLoopWindowTarget,
|
||||
Window as LinuxWindow,
|
||||
Backend, EventLoopWindowTarget as LinuxEventLoopWindowTarget, Window as LinuxWindow,
|
||||
};
|
||||
|
||||
// TODO: stupid hack so that glutin can do its work
|
||||
|
@ -93,100 +92,42 @@ impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Additional methods on `EventLoop` that are specific to Unix.
|
||||
pub trait EventLoopExtUnix {
|
||||
/// Builds a new `EventLoop` that is forced to use X11.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If called outside the main thread. To initialize an X11 event loop outside
|
||||
/// the main thread, use [`new_x11_any_thread`](#tymethod.new_x11_any_thread).
|
||||
/// Additional methods on [`EventLoopBuilder`] that are specific to Unix.
|
||||
pub trait EventLoopBuilderExtUnix {
|
||||
/// Force using X11.
|
||||
#[cfg(feature = "x11")]
|
||||
fn new_x11() -> Result<Self, XNotSupported>
|
||||
where
|
||||
Self: Sized;
|
||||
fn with_x11(&mut self) -> &mut Self;
|
||||
|
||||
/// Builds a new `EventLoop` that is forced to use Wayland.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If called outside the main thread. To initialize a Wayland event loop outside
|
||||
/// the main thread, use [`new_wayland_any_thread`](#tymethod.new_wayland_any_thread).
|
||||
/// Force using Wayland.
|
||||
#[cfg(feature = "wayland")]
|
||||
fn new_wayland() -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
fn with_wayland(&mut self) -> &mut Self;
|
||||
|
||||
/// Builds a new `EventLoop` on any thread.
|
||||
/// Whether to allow the event loop to be created off of the main thread.
|
||||
///
|
||||
/// This method bypasses the cross-platform compatibility requirement
|
||||
/// that `EventLoop` be created on the main thread.
|
||||
fn new_any_thread() -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Builds a new X11 `EventLoop` on any thread.
|
||||
///
|
||||
/// This method bypasses the cross-platform compatibility requirement
|
||||
/// that `EventLoop` be created on the main thread.
|
||||
#[cfg(feature = "x11")]
|
||||
fn new_x11_any_thread() -> Result<Self, XNotSupported>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Builds a new Wayland `EventLoop` on any thread.
|
||||
///
|
||||
/// This method bypasses the cross-platform compatibility requirement
|
||||
/// that `EventLoop` be created on the main thread.
|
||||
#[cfg(feature = "wayland")]
|
||||
fn new_wayland_any_thread() -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
/// By default, the window is only allowed to be created on the main
|
||||
/// thread, to make platform compatibility easier.
|
||||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
|
||||
}
|
||||
|
||||
fn wrap_ev<T>(event_loop: LinuxEventLoop<T>) -> EventLoop<T> {
|
||||
EventLoop {
|
||||
event_loop,
|
||||
_marker: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> EventLoopExtUnix for EventLoop<T> {
|
||||
#[inline]
|
||||
fn new_any_thread() -> Self {
|
||||
wrap_ev(LinuxEventLoop::new_any_thread())
|
||||
}
|
||||
|
||||
impl<T> EventLoopBuilderExtUnix for EventLoopBuilder<T> {
|
||||
#[inline]
|
||||
#[cfg(feature = "x11")]
|
||||
fn new_x11_any_thread() -> Result<Self, XNotSupported> {
|
||||
LinuxEventLoop::new_x11_any_thread().map(wrap_ev)
|
||||
fn with_x11(&mut self) -> &mut Self {
|
||||
self.platform_specific.forced_backend = Some(Backend::X);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(feature = "wayland")]
|
||||
fn new_wayland_any_thread() -> Self {
|
||||
wrap_ev(
|
||||
LinuxEventLoop::new_wayland_any_thread()
|
||||
// TODO: propagate
|
||||
.expect("failed to open Wayland connection"),
|
||||
)
|
||||
fn with_wayland(&mut self) -> &mut Self {
|
||||
self.platform_specific.forced_backend = Some(Backend::Wayland);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(feature = "x11")]
|
||||
fn new_x11() -> Result<Self, XNotSupported> {
|
||||
LinuxEventLoop::new_x11().map(wrap_ev)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(feature = "wayland")]
|
||||
fn new_wayland() -> Self {
|
||||
wrap_ev(
|
||||
LinuxEventLoop::new_wayland()
|
||||
// TODO: propagate
|
||||
.expect("failed to open Wayland connection"),
|
||||
)
|
||||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
|
||||
self.platform_specific.any_thread = any_thread;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,62 +9,61 @@ use winapi::shared::windef::{HMENU, HWND};
|
|||
use crate::{
|
||||
dpi::PhysicalSize,
|
||||
event::DeviceId,
|
||||
event_loop::EventLoop,
|
||||
event_loop::EventLoopBuilder,
|
||||
monitor::MonitorHandle,
|
||||
platform_impl::{EventLoop as WindowsEventLoop, Parent, WinIcon},
|
||||
platform_impl::{Parent, WinIcon},
|
||||
window::{BadIcon, Icon, Theme, Window, WindowBuilder},
|
||||
};
|
||||
|
||||
/// Additional methods on `EventLoop` that are specific to Windows.
|
||||
pub trait EventLoopExtWindows {
|
||||
/// Creates an event loop off of the main thread.
|
||||
pub trait EventLoopBuilderExtWindows {
|
||||
/// Whether to allow the event loop to be created off of the main thread.
|
||||
///
|
||||
/// By default, the window is only allowed to be created on the main
|
||||
/// thread, to make platform compatibility easier.
|
||||
///
|
||||
/// # `Window` caveats
|
||||
///
|
||||
/// Note that any `Window` created on the new thread will be destroyed when the thread
|
||||
/// terminates. Attempting to use a `Window` after its parent thread terminates has
|
||||
/// unspecified, although explicitly not undefined, behavior.
|
||||
fn new_any_thread() -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Creates a DPI-unaware event loop off of the main thread.
|
||||
/// Whether to enable process-wide DPI awareness.
|
||||
///
|
||||
/// The `Window` caveats in [`new_any_thread`](EventLoopExtWindows::new_any_thread) also apply here.
|
||||
fn new_dpi_unaware_any_thread() -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
/// By default, `winit` will attempt to enable process-wide DPI awareness. If
|
||||
/// that's undesirable, you can disable it with this function.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Disable process-wide DPI awareness.
|
||||
///
|
||||
/// ```
|
||||
/// use winit::event_loop::EventLoopBuilder;
|
||||
/// #[cfg(target_os = "windows")]
|
||||
/// use winit::platform::windows::EventLoopBuilderExtWindows;
|
||||
///
|
||||
/// let mut builder = EventLoopBuilder::new();
|
||||
/// #[cfg(target_os = "windows")]
|
||||
/// builder.with_dpi_aware(false);
|
||||
/// # if false { // We can't test this part
|
||||
/// let event_loop = builder.build();
|
||||
/// # }
|
||||
/// ```
|
||||
fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self;
|
||||
}
|
||||
|
||||
impl<T> EventLoopExtWindows for EventLoop<T> {
|
||||
impl<T> EventLoopBuilderExtWindows for EventLoopBuilder<T> {
|
||||
#[inline]
|
||||
fn new_any_thread() -> Self {
|
||||
EventLoop {
|
||||
event_loop: WindowsEventLoop::new_any_thread(),
|
||||
_marker: ::std::marker::PhantomData,
|
||||
}
|
||||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
|
||||
self.platform_specific.any_thread = any_thread;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn new_dpi_unaware() -> Self {
|
||||
EventLoop {
|
||||
event_loop: WindowsEventLoop::new_dpi_unaware(),
|
||||
_marker: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn new_dpi_unaware_any_thread() -> Self {
|
||||
EventLoop {
|
||||
event_loop: WindowsEventLoop::new_dpi_unaware_any_thread(),
|
||||
_marker: ::std::marker::PhantomData,
|
||||
}
|
||||
fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self {
|
||||
self.platform_specific.dpi_aware = dpi_aware;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,9 @@ pub struct EventLoop<T: 'static> {
|
|||
running: bool,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Hash)]
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||
|
||||
macro_rules! call_event_handler {
|
||||
( $event_handler:expr, $window_target:expr, $cf:expr, $event:expr ) => {{
|
||||
if let ControlFlow::ExitWithCode(code) = $cf {
|
||||
|
@ -82,7 +85,7 @@ macro_rules! call_event_handler {
|
|||
}
|
||||
|
||||
impl<T: 'static> EventLoop<T> {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||
Self {
|
||||
window_target: event_loop::EventLoopWindowTarget {
|
||||
p: EventLoopWindowTarget {
|
||||
|
|
|
@ -69,8 +69,11 @@ pub struct EventLoop<T: 'static> {
|
|||
window_target: RootEventLoopWindowTarget<T>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Hash)]
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||
|
||||
impl<T: 'static> EventLoop<T> {
|
||||
pub fn new() -> EventLoop<T> {
|
||||
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> EventLoop<T> {
|
||||
static mut SINGLETON_INIT: bool = false;
|
||||
unsafe {
|
||||
assert_main_thread!("`EventLoop` can only be created on the main thread on iOS");
|
||||
|
|
|
@ -78,8 +78,10 @@ mod window;
|
|||
|
||||
use std::fmt;
|
||||
|
||||
pub use self::{
|
||||
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
|
||||
pub(crate) use self::{
|
||||
event_loop::{
|
||||
EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes,
|
||||
},
|
||||
monitor::{MonitorHandle, VideoMode},
|
||||
window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
|
||||
};
|
||||
|
|
|
@ -49,6 +49,29 @@ pub mod x11;
|
|||
/// If this variable is set with any other value, winit will panic.
|
||||
const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND";
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Hash)]
|
||||
pub(crate) enum Backend {
|
||||
#[cfg(feature = "x11")]
|
||||
X,
|
||||
#[cfg(feature = "wayland")]
|
||||
Wayland,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Hash)]
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {
|
||||
pub(crate) forced_backend: Option<Backend>,
|
||||
pub(crate) any_thread: bool,
|
||||
}
|
||||
|
||||
impl Default for PlatformSpecificEventLoopAttributes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
forced_backend: None,
|
||||
any_thread: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PlatformSpecificWindowBuilderAttributes {
|
||||
#[cfg(feature = "x11")]
|
||||
|
@ -568,13 +591,28 @@ impl<T: 'static> Clone for EventLoopProxy<T> {
|
|||
}
|
||||
|
||||
impl<T: 'static> EventLoop<T> {
|
||||
pub fn new() -> EventLoop<T> {
|
||||
assert_is_main_thread("new_any_thread");
|
||||
|
||||
EventLoop::new_any_thread()
|
||||
pub(crate) fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||
if !attributes.any_thread && !is_main_thread() {
|
||||
panic!(
|
||||
"Initializing the event loop outside of the main thread is a significant \
|
||||
cross-platform compatibility hazard. If you absolutely need to create an \
|
||||
EventLoop on a different thread, you can use the \
|
||||
`EventLoopBuilderExtUnix::any_thread` function."
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "x11")]
|
||||
if attributes.forced_backend == Some(Backend::X) {
|
||||
// TODO: Propagate
|
||||
return EventLoop::new_x11_any_thread().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
if attributes.forced_backend == Some(Backend::Wayland) {
|
||||
// TODO: Propagate
|
||||
return EventLoop::new_wayland_any_thread().expect("failed to open Wayland connection");
|
||||
}
|
||||
|
||||
pub fn new_any_thread() -> EventLoop<T> {
|
||||
if let Ok(env_var) = env::var(BACKEND_PREFERENCE_ENV_VAR) {
|
||||
match env_var.as_str() {
|
||||
"x11" => {
|
||||
|
@ -623,26 +661,12 @@ impl<T: 'static> EventLoop<T> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
pub fn new_wayland() -> Result<EventLoop<T>, Box<dyn Error>> {
|
||||
assert_is_main_thread("new_wayland_any_thread");
|
||||
|
||||
EventLoop::new_wayland_any_thread()
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
pub fn new_wayland_any_thread() -> Result<EventLoop<T>, Box<dyn Error>> {
|
||||
fn new_wayland_any_thread() -> Result<EventLoop<T>, Box<dyn Error>> {
|
||||
wayland::EventLoop::new().map(EventLoop::Wayland)
|
||||
}
|
||||
|
||||
#[cfg(feature = "x11")]
|
||||
pub fn new_x11() -> Result<EventLoop<T>, XNotSupported> {
|
||||
assert_is_main_thread("new_x11_any_thread");
|
||||
|
||||
EventLoop::new_x11_any_thread()
|
||||
}
|
||||
|
||||
#[cfg(feature = "x11")]
|
||||
pub fn new_x11_any_thread() -> Result<EventLoop<T>, XNotSupported> {
|
||||
fn new_x11_any_thread() -> Result<EventLoop<T>, XNotSupported> {
|
||||
let xconn = match X11_BACKEND.lock().as_ref() {
|
||||
Ok(xconn) => xconn.clone(),
|
||||
Err(err) => return Err(err.clone()),
|
||||
|
@ -750,17 +774,6 @@ fn sticky_exit_callback<T, F>(
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_is_main_thread(suggested_method: &str) {
|
||||
if !is_main_thread() {
|
||||
panic!(
|
||||
"Initializing the event loop outside of the main thread is a significant \
|
||||
cross-platform compatibility hazard. If you really, absolutely need to create an \
|
||||
EventLoop on a different thread, please use the `EventLoopExtUnix::{}` function.",
|
||||
suggested_method
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn is_main_thread() -> bool {
|
||||
use libc::{c_long, getpid, syscall, SYS_gettid};
|
||||
|
|
|
@ -13,12 +13,8 @@ use std::{
|
|||
static AUX_DELEGATE_STATE_NAME: &str = "auxState";
|
||||
|
||||
pub struct AuxDelegateState {
|
||||
/// We store this value in order to be able to defer setting the activation policy until
|
||||
/// after the app has finished launching. If the activation policy is set earlier, the
|
||||
/// menubar is initially unresponsive on macOS 10.15 for example.
|
||||
pub activation_policy: ActivationPolicy,
|
||||
|
||||
pub create_default_menu: bool,
|
||||
pub default_menu: bool,
|
||||
}
|
||||
|
||||
pub struct AppDelegateClass(pub *const Class);
|
||||
|
@ -54,11 +50,12 @@ extern "C" fn new(class: &Class, _: Sel) -> id {
|
|||
unsafe {
|
||||
let this: id = msg_send![class, alloc];
|
||||
let this: id = msg_send![this, init];
|
||||
// TODO: Remove the need for this initialization here
|
||||
(*this).set_ivar(
|
||||
AUX_DELEGATE_STATE_NAME,
|
||||
Box::into_raw(Box::new(RefCell::new(AuxDelegateState {
|
||||
activation_policy: ActivationPolicy::Regular,
|
||||
create_default_menu: true,
|
||||
default_menu: true,
|
||||
}))) as *mut c_void,
|
||||
);
|
||||
this
|
||||
|
|
|
@ -296,7 +296,7 @@ impl AppState {
|
|||
};
|
||||
HANDLER.set_ready();
|
||||
HANDLER.waker().start();
|
||||
let create_default_menu = unsafe { get_aux_state_mut(app_delegate).create_default_menu };
|
||||
let create_default_menu = unsafe { get_aux_state_mut(app_delegate).default_menu };
|
||||
if create_default_menu {
|
||||
// The menubar initialization should be before the `NewEvents` event, to allow
|
||||
// overriding of the default menu even if it's created
|
||||
|
@ -486,7 +486,7 @@ fn apply_activation_policy(app_delegate: &Object) {
|
|||
let ns_app = NSApp();
|
||||
// We need to delay setting the activation policy and activating the app
|
||||
// until `applicationDidFinishLaunching` has been called. Otherwise the
|
||||
// menu bar won't be interactable.
|
||||
// menu bar is initially unresponsive on macOS 10.15.
|
||||
let act_pol = get_aux_state_mut(app_delegate).activation_policy;
|
||||
ns_app.setActivationPolicy_(match act_pol {
|
||||
ActivationPolicy::Regular => NSApplicationActivationPolicyRegular,
|
||||
|
|
|
@ -22,7 +22,10 @@ use crate::{
|
|||
event::Event,
|
||||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootWindowTarget},
|
||||
monitor::MonitorHandle as RootMonitorHandle,
|
||||
platform_impl::platform::{
|
||||
platform::macos::ActivationPolicy,
|
||||
platform_impl::{
|
||||
get_aux_state_mut,
|
||||
platform::{
|
||||
app::APP_CLASS,
|
||||
app_delegate::APP_DELEGATE_CLASS,
|
||||
app_state::{AppState, Callback},
|
||||
|
@ -30,6 +33,7 @@ use crate::{
|
|||
observer::*,
|
||||
util::IdRef,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -100,7 +104,9 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
}
|
||||
|
||||
pub struct EventLoop<T: 'static> {
|
||||
pub(crate) delegate: IdRef,
|
||||
/// The delegate is only weakly referenced by NSApplication, so we keep
|
||||
/// it around here as well.
|
||||
_delegate: IdRef,
|
||||
|
||||
window_target: Rc<RootWindowTarget<T>>,
|
||||
panic_info: Rc<PanicInfo>,
|
||||
|
@ -114,8 +120,23 @@ pub struct EventLoop<T: 'static> {
|
|||
_callback: Option<Rc<Callback<T>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Hash)]
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {
|
||||
pub(crate) activation_policy: ActivationPolicy,
|
||||
pub(crate) default_menu: bool,
|
||||
}
|
||||
|
||||
impl Default for PlatformSpecificEventLoopAttributes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
activation_policy: Default::default(), // Regular
|
||||
default_menu: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> EventLoop<T> {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||
let delegate = unsafe {
|
||||
let is_main_thread: BOOL = msg_send!(class!(NSThread), isMainThread);
|
||||
if is_main_thread == NO {
|
||||
|
@ -129,15 +150,21 @@ impl<T> EventLoop<T> {
|
|||
let app: id = msg_send![APP_CLASS.0, sharedApplication];
|
||||
|
||||
let delegate = IdRef::new(msg_send![APP_DELEGATE_CLASS.0, new]);
|
||||
|
||||
let mut aux_state = get_aux_state_mut(&**delegate);
|
||||
aux_state.activation_policy = attributes.activation_policy;
|
||||
aux_state.default_menu = attributes.default_menu;
|
||||
|
||||
autoreleasepool(|| {
|
||||
let _: () = msg_send![app, setDelegate:*delegate];
|
||||
});
|
||||
|
||||
delegate
|
||||
};
|
||||
let panic_info: Rc<PanicInfo> = Default::default();
|
||||
setup_control_flow_observers(Rc::downgrade(&panic_info));
|
||||
EventLoop {
|
||||
delegate,
|
||||
_delegate: delegate,
|
||||
window_target: Rc::new(RootWindowTarget {
|
||||
p: Default::default(),
|
||||
_marker: PhantomData,
|
||||
|
|
|
@ -18,9 +18,12 @@ mod window_delegate;
|
|||
|
||||
use std::{fmt, ops::Deref, sync::Arc};
|
||||
|
||||
pub use self::{
|
||||
app_delegate::{get_aux_state_mut, AuxDelegateState},
|
||||
event_loop::{EventLoop, EventLoopWindowTarget, Proxy as EventLoopProxy},
|
||||
pub(crate) use self::{
|
||||
app_delegate::get_aux_state_mut,
|
||||
event_loop::{
|
||||
EventLoop, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes,
|
||||
Proxy as EventLoopProxy,
|
||||
},
|
||||
monitor::{MonitorHandle, VideoMode},
|
||||
window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, UnownedWindow},
|
||||
};
|
||||
|
|
|
@ -16,8 +16,11 @@ pub struct EventLoop<T: 'static> {
|
|||
elw: root::EventLoopWindowTarget<T>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Hash)]
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||
|
||||
impl<T> EventLoop<T> {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||
EventLoop {
|
||||
elw: root::EventLoopWindowTarget {
|
||||
p: WindowTarget::new(),
|
||||
|
|
|
@ -28,8 +28,9 @@ mod backend;
|
|||
|
||||
pub use self::device::Id as DeviceId;
|
||||
pub use self::error::OsError;
|
||||
pub use self::event_loop::{
|
||||
EventLoop, Proxy as EventLoopProxy, WindowTarget as EventLoopWindowTarget,
|
||||
pub(crate) use self::event_loop::{
|
||||
EventLoop, PlatformSpecificEventLoopAttributes, Proxy as EventLoopProxy,
|
||||
WindowTarget as EventLoopWindowTarget,
|
||||
};
|
||||
pub use self::monitor::{Handle as MonitorHandle, Mode as VideoMode};
|
||||
pub use self::window::{
|
||||
|
|
|
@ -113,48 +113,44 @@ pub struct EventLoop<T: 'static> {
|
|||
window_target: RootELW<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Hash)]
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {
|
||||
pub(crate) any_thread: bool,
|
||||
pub(crate) dpi_aware: bool,
|
||||
}
|
||||
|
||||
impl Default for PlatformSpecificEventLoopAttributes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
any_thread: false,
|
||||
dpi_aware: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventLoopWindowTarget<T: 'static> {
|
||||
thread_id: DWORD,
|
||||
thread_msg_target: HWND,
|
||||
pub(crate) runner_shared: EventLoopRunnerShared<T>,
|
||||
}
|
||||
|
||||
macro_rules! main_thread_check {
|
||||
($fn_name:literal) => {{
|
||||
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
|
||||
if thread_id != main_thread_id() {
|
||||
panic!(concat!(
|
||||
"Initializing the event loop outside of the main thread is a significant \
|
||||
cross-platform compatibility hazard. If you really, absolutely need to create an \
|
||||
EventLoop on a different thread, please use the `EventLoopExtWindows::",
|
||||
$fn_name,
|
||||
"` function."
|
||||
));
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
impl<T: 'static> EventLoop<T> {
|
||||
pub fn new() -> EventLoop<T> {
|
||||
main_thread_check!("new_any_thread");
|
||||
|
||||
Self::new_any_thread()
|
||||
}
|
||||
|
||||
pub fn new_any_thread() -> EventLoop<T> {
|
||||
become_dpi_aware();
|
||||
Self::new_dpi_unaware_any_thread()
|
||||
}
|
||||
|
||||
pub fn new_dpi_unaware() -> EventLoop<T> {
|
||||
main_thread_check!("new_dpi_unaware_any_thread");
|
||||
|
||||
Self::new_dpi_unaware_any_thread()
|
||||
}
|
||||
|
||||
pub fn new_dpi_unaware_any_thread() -> EventLoop<T> {
|
||||
pub(crate) fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
|
||||
|
||||
if !attributes.any_thread && thread_id != main_thread_id() {
|
||||
panic!(
|
||||
"Initializing the event loop outside of the main thread is a significant \
|
||||
cross-platform compatibility hazard. If you absolutely need to create an \
|
||||
EventLoop on a different thread, you can use the \
|
||||
`EventLoopBuilderExtWindows::any_thread` function."
|
||||
);
|
||||
}
|
||||
|
||||
if attributes.dpi_aware {
|
||||
become_dpi_aware();
|
||||
}
|
||||
|
||||
let thread_msg_target = create_event_target_window::<T>();
|
||||
|
||||
let send_thread_msg_target = thread_msg_target as usize;
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
use winapi::{self, shared::windef::HMENU, shared::windef::HWND};
|
||||
|
||||
pub use self::{
|
||||
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
|
||||
pub(crate) use self::{
|
||||
event_loop::{
|
||||
EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes,
|
||||
},
|
||||
icon::WinIcon,
|
||||
monitor::{MonitorHandle, VideoMode},
|
||||
window::Window,
|
||||
|
|
|
@ -83,7 +83,7 @@ impl WindowId {
|
|||
}
|
||||
}
|
||||
|
||||
/// Object that allows you to build windows.
|
||||
/// Object that allows building windows.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct WindowBuilder {
|
||||
/// The attributes to use to create the window.
|
||||
|
|
Loading…
Reference in a new issue