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`.
|
- **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.
|
- 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.
|
- **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)
|
# 0.26.1 (2022-01-05)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ fn main() {
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{Event, WindowEvent},
|
event::{Event, WindowEvent},
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::{ControlFlow, EventLoopBuilder},
|
||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleLogger::new().init().unwrap();
|
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()
|
let _window = WindowBuilder::new()
|
||||||
.with_title("A fantastic window!")
|
.with_title("A fantastic window!")
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
//! [event_loop_proxy]: crate::event_loop::EventLoopProxy
|
//! [event_loop_proxy]: crate::event_loop::EventLoopProxy
|
||||||
//! [send_event]: crate::event_loop::EventLoopProxy::send_event
|
//! [send_event]: crate::event_loop::EventLoopProxy::send_event
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::{error, fmt};
|
use std::{error, fmt};
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ use crate::{event::Event, monitor::MonitorHandle, platform_impl};
|
||||||
///
|
///
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop<T: 'static> {
|
||||||
pub(crate) event_loop: platform_impl::EventLoop<T>,
|
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`.
|
/// Target that associates windows with an `EventLoop`.
|
||||||
|
@ -42,7 +43,62 @@ pub struct EventLoop<T: 'static> {
|
||||||
/// `&EventLoop`.
|
/// `&EventLoop`.
|
||||||
pub struct EventLoopWindowTarget<T: 'static> {
|
pub struct EventLoopWindowTarget<T: 'static> {
|
||||||
pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
|
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> {
|
impl<T> fmt::Debug for EventLoop<T> {
|
||||||
|
@ -119,41 +175,17 @@ impl Default for ControlFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoop<()> {
|
impl EventLoop<()> {
|
||||||
/// Builds a new event loop with a `()` as the user event type.
|
/// Alias for `EventLoopBuilder::new().build()`.
|
||||||
///
|
#[inline]
|
||||||
/// ***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.
|
|
||||||
pub fn new() -> EventLoop<()> {
|
pub fn new() -> EventLoop<()> {
|
||||||
EventLoop::<()>::with_user_event()
|
EventLoopBuilder::new().build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoop<T> {
|
impl<T> EventLoop<T> {
|
||||||
/// Builds a new event loop.
|
#[deprecated = "Use `EventLoopBuiler::<T>::with_user_event().build()` instead."]
|
||||||
///
|
|
||||||
/// All caveats documented in [`EventLoop::new`] apply to this function.
|
|
||||||
///
|
|
||||||
/// ## Platform-specific
|
|
||||||
///
|
|
||||||
/// - **iOS:** Can only be called on the main thread.
|
|
||||||
pub fn with_user_event() -> EventLoop<T> {
|
pub fn with_user_event() -> EventLoop<T> {
|
||||||
EventLoop {
|
EventLoopBuilder::<T>::with_user_event().build()
|
||||||
event_loop: platform_impl::EventLoop::new(),
|
|
||||||
_marker: ::std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hijacks the calling thread and initializes the winit event loop with the provided
|
/// 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::{
|
use crate::{
|
||||||
dpi::LogicalSize,
|
dpi::LogicalSize,
|
||||||
event_loop::{EventLoop, EventLoopWindowTarget},
|
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
|
||||||
monitor::MonitorHandle,
|
monitor::MonitorHandle,
|
||||||
platform_impl::get_aux_state_mut,
|
|
||||||
window::{Window, WindowBuilder},
|
window::{Window, WindowBuilder},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,7 +73,7 @@ impl WindowExtMacOS for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Corresponds to `NSApplicationActivationPolicy`.
|
/// Corresponds to `NSApplicationActivationPolicy`.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum ActivationPolicy {
|
pub enum ActivationPolicy {
|
||||||
/// Corresponds to `NSApplicationActivationPolicyRegular`.
|
/// Corresponds to `NSApplicationActivationPolicyRegular`.
|
||||||
Regular,
|
Regular,
|
||||||
|
@ -179,36 +178,63 @@ impl WindowBuilderExtMacOS for WindowBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EventLoopExtMacOS {
|
pub trait EventLoopBuilderExtMacOS {
|
||||||
/// Sets the activation policy for the application. It is set to
|
/// Sets the activation policy for the application.
|
||||||
/// `NSApplicationActivationPolicyRegular` by default.
|
|
||||||
///
|
///
|
||||||
/// This function only takes effect if it's called before calling [`run`](crate::event_loop::EventLoop::run) or
|
/// It is set to [`ActivationPolicy::Regular`] by default.
|
||||||
/// [`run_return`](crate::platform::run_return::EventLoopExtRunReturn::run_return)
|
///
|
||||||
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);
|
/// # 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
|
/// # Example
|
||||||
/// [`run`](crate::event_loop::EventLoop::run) or
|
///
|
||||||
/// [`run_return`](crate::platform::run_return::EventLoopExtRunReturn::run_return)
|
/// Disable creating a default menubar.
|
||||||
fn enable_default_menu_creation(&mut self, enable: bool);
|
///
|
||||||
|
/// ```
|
||||||
|
/// 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]
|
#[inline]
|
||||||
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
|
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self {
|
||||||
unsafe {
|
self.platform_specific.activation_policy = activation_policy;
|
||||||
get_aux_state_mut(&**self.event_loop.delegate).activation_policy = activation_policy;
|
self
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn enable_default_menu_creation(&mut self, enable: bool) {
|
fn with_default_menu(&mut self, enable: bool) -> &mut Self {
|
||||||
unsafe {
|
self.platform_specific.default_menu = enable;
|
||||||
get_aux_state_mut(&**self.event_loop.delegate).create_default_menu = enable;
|
self
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::os::raw;
|
||||||
use std::{ptr, sync::Arc};
|
use std::{ptr, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
event_loop::{EventLoop, EventLoopWindowTarget},
|
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
|
||||||
monitor::MonitorHandle,
|
monitor::MonitorHandle,
|
||||||
window::{Window, WindowBuilder},
|
window::{Window, WindowBuilder},
|
||||||
};
|
};
|
||||||
|
@ -21,8 +21,7 @@ use crate::dpi::Size;
|
||||||
#[cfg(feature = "x11")]
|
#[cfg(feature = "x11")]
|
||||||
use crate::platform_impl::x11::{ffi::XVisualInfo, XConnection};
|
use crate::platform_impl::x11::{ffi::XVisualInfo, XConnection};
|
||||||
use crate::platform_impl::{
|
use crate::platform_impl::{
|
||||||
EventLoop as LinuxEventLoop, EventLoopWindowTarget as LinuxEventLoopWindowTarget,
|
Backend, EventLoopWindowTarget as LinuxEventLoopWindowTarget, Window as LinuxWindow,
|
||||||
Window as LinuxWindow,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: stupid hack so that glutin can do its work
|
// 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.
|
/// Additional methods on [`EventLoopBuilder`] that are specific to Unix.
|
||||||
pub trait EventLoopExtUnix {
|
pub trait EventLoopBuilderExtUnix {
|
||||||
/// Builds a new `EventLoop` that is forced to use X11.
|
/// Force using 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).
|
|
||||||
#[cfg(feature = "x11")]
|
#[cfg(feature = "x11")]
|
||||||
fn new_x11() -> Result<Self, XNotSupported>
|
fn with_x11(&mut self) -> &mut Self;
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
|
|
||||||
/// Builds a new `EventLoop` that is forced to use Wayland.
|
/// Force using 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).
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
fn new_wayland() -> Self
|
fn with_wayland(&mut self) -> &mut Self;
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
|
|
||||||
/// 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
|
/// By default, the window is only allowed to be created on the main
|
||||||
/// that `EventLoop` be created on the main thread.
|
/// thread, to make platform compatibility easier.
|
||||||
fn new_any_thread() -> Self
|
fn with_any_thread(&mut self, any_thread: bool) -> &mut 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_ev<T>(event_loop: LinuxEventLoop<T>) -> EventLoop<T> {
|
impl<T> EventLoopBuilderExtUnix for EventLoopBuilder<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())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(feature = "x11")]
|
#[cfg(feature = "x11")]
|
||||||
fn new_x11_any_thread() -> Result<Self, XNotSupported> {
|
fn with_x11(&mut self) -> &mut Self {
|
||||||
LinuxEventLoop::new_x11_any_thread().map(wrap_ev)
|
self.platform_specific.forced_backend = Some(Backend::X);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
fn new_wayland_any_thread() -> Self {
|
fn with_wayland(&mut self) -> &mut Self {
|
||||||
wrap_ev(
|
self.platform_specific.forced_backend = Some(Backend::Wayland);
|
||||||
LinuxEventLoop::new_wayland_any_thread()
|
self
|
||||||
// TODO: propagate
|
|
||||||
.expect("failed to open Wayland connection"),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(feature = "x11")]
|
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
|
||||||
fn new_x11() -> Result<Self, XNotSupported> {
|
self.platform_specific.any_thread = any_thread;
|
||||||
LinuxEventLoop::new_x11().map(wrap_ev)
|
self
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[cfg(feature = "wayland")]
|
|
||||||
fn new_wayland() -> Self {
|
|
||||||
wrap_ev(
|
|
||||||
LinuxEventLoop::new_wayland()
|
|
||||||
// TODO: propagate
|
|
||||||
.expect("failed to open Wayland connection"),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,62 +9,61 @@ use winapi::shared::windef::{HMENU, HWND};
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::PhysicalSize,
|
dpi::PhysicalSize,
|
||||||
event::DeviceId,
|
event::DeviceId,
|
||||||
event_loop::EventLoop,
|
event_loop::EventLoopBuilder,
|
||||||
monitor::MonitorHandle,
|
monitor::MonitorHandle,
|
||||||
platform_impl::{EventLoop as WindowsEventLoop, Parent, WinIcon},
|
platform_impl::{Parent, WinIcon},
|
||||||
window::{BadIcon, Icon, Theme, Window, WindowBuilder},
|
window::{BadIcon, Icon, Theme, Window, WindowBuilder},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Additional methods on `EventLoop` that are specific to Windows.
|
/// Additional methods on `EventLoop` that are specific to Windows.
|
||||||
pub trait EventLoopExtWindows {
|
pub trait EventLoopBuilderExtWindows {
|
||||||
/// Creates an event loop off of the main thread.
|
/// 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
|
/// # `Window` caveats
|
||||||
///
|
///
|
||||||
/// Note that any `Window` created on the new thread will be destroyed when the thread
|
/// 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
|
/// terminates. Attempting to use a `Window` after its parent thread terminates has
|
||||||
/// unspecified, although explicitly not undefined, behavior.
|
/// unspecified, although explicitly not undefined, behavior.
|
||||||
fn new_any_thread() -> Self
|
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
|
|
||||||
/// By default, winit on Windows will attempt to enable process-wide DPI awareness. If that's
|
/// Whether to enable process-wide DPI awareness.
|
||||||
/// 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.
|
|
||||||
///
|
///
|
||||||
/// The `Window` caveats in [`new_any_thread`](EventLoopExtWindows::new_any_thread) also apply here.
|
/// By default, `winit` will attempt to enable process-wide DPI awareness. If
|
||||||
fn new_dpi_unaware_any_thread() -> Self
|
/// that's undesirable, you can disable it with this function.
|
||||||
where
|
///
|
||||||
Self: Sized;
|
/// # 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]
|
#[inline]
|
||||||
fn new_any_thread() -> Self {
|
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
|
||||||
EventLoop {
|
self.platform_specific.any_thread = any_thread;
|
||||||
event_loop: WindowsEventLoop::new_any_thread(),
|
self
|
||||||
_marker: ::std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new_dpi_unaware() -> Self {
|
fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self {
|
||||||
EventLoop {
|
self.platform_specific.dpi_aware = dpi_aware;
|
||||||
event_loop: WindowsEventLoop::new_dpi_unaware(),
|
self
|
||||||
_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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,9 @@ pub struct EventLoop<T: 'static> {
|
||||||
running: bool,
|
running: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Hash)]
|
||||||
|
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||||
|
|
||||||
macro_rules! call_event_handler {
|
macro_rules! call_event_handler {
|
||||||
( $event_handler:expr, $window_target:expr, $cf:expr, $event:expr ) => {{
|
( $event_handler:expr, $window_target:expr, $cf:expr, $event:expr ) => {{
|
||||||
if let ControlFlow::ExitWithCode(code) = $cf {
|
if let ControlFlow::ExitWithCode(code) = $cf {
|
||||||
|
@ -82,7 +85,7 @@ macro_rules! call_event_handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl<T: 'static> EventLoop<T> {
|
||||||
pub fn new() -> Self {
|
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||||
Self {
|
Self {
|
||||||
window_target: event_loop::EventLoopWindowTarget {
|
window_target: event_loop::EventLoopWindowTarget {
|
||||||
p: EventLoopWindowTarget {
|
p: EventLoopWindowTarget {
|
||||||
|
|
|
@ -69,8 +69,11 @@ pub struct EventLoop<T: 'static> {
|
||||||
window_target: RootEventLoopWindowTarget<T>,
|
window_target: RootEventLoopWindowTarget<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Hash)]
|
||||||
|
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl<T: 'static> EventLoop<T> {
|
||||||
pub fn new() -> EventLoop<T> {
|
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> EventLoop<T> {
|
||||||
static mut SINGLETON_INIT: bool = false;
|
static mut SINGLETON_INIT: bool = false;
|
||||||
unsafe {
|
unsafe {
|
||||||
assert_main_thread!("`EventLoop` can only be created on the main thread on iOS");
|
assert_main_thread!("`EventLoop` can only be created on the main thread on iOS");
|
||||||
|
|
|
@ -78,8 +78,10 @@ mod window;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub use self::{
|
pub(crate) use self::{
|
||||||
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
|
event_loop::{
|
||||||
|
EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes,
|
||||||
|
},
|
||||||
monitor::{MonitorHandle, VideoMode},
|
monitor::{MonitorHandle, VideoMode},
|
||||||
window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
|
window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,6 +49,29 @@ pub mod x11;
|
||||||
/// If this variable is set with any other value, winit will panic.
|
/// If this variable is set with any other value, winit will panic.
|
||||||
const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND";
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct PlatformSpecificWindowBuilderAttributes {
|
pub struct PlatformSpecificWindowBuilderAttributes {
|
||||||
#[cfg(feature = "x11")]
|
#[cfg(feature = "x11")]
|
||||||
|
@ -568,13 +591,28 @@ impl<T: 'static> Clone for EventLoopProxy<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl<T: 'static> EventLoop<T> {
|
||||||
pub fn new() -> EventLoop<T> {
|
pub(crate) fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||||
assert_is_main_thread("new_any_thread");
|
if !attributes.any_thread && !is_main_thread() {
|
||||||
|
panic!(
|
||||||
EventLoop::new_any_thread()
|
"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) {
|
if let Ok(env_var) = env::var(BACKEND_PREFERENCE_ENV_VAR) {
|
||||||
match env_var.as_str() {
|
match env_var.as_str() {
|
||||||
"x11" => {
|
"x11" => {
|
||||||
|
@ -623,26 +661,12 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
pub fn new_wayland() -> Result<EventLoop<T>, Box<dyn Error>> {
|
fn new_wayland_any_thread() -> 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>> {
|
|
||||||
wayland::EventLoop::new().map(EventLoop::Wayland)
|
wayland::EventLoop::new().map(EventLoop::Wayland)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "x11")]
|
#[cfg(feature = "x11")]
|
||||||
pub fn new_x11() -> Result<EventLoop<T>, XNotSupported> {
|
fn new_x11_any_thread() -> 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> {
|
|
||||||
let xconn = match X11_BACKEND.lock().as_ref() {
|
let xconn = match X11_BACKEND.lock().as_ref() {
|
||||||
Ok(xconn) => xconn.clone(),
|
Ok(xconn) => xconn.clone(),
|
||||||
Err(err) => return Err(err.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")]
|
#[cfg(target_os = "linux")]
|
||||||
fn is_main_thread() -> bool {
|
fn is_main_thread() -> bool {
|
||||||
use libc::{c_long, getpid, syscall, SYS_gettid};
|
use libc::{c_long, getpid, syscall, SYS_gettid};
|
||||||
|
|
|
@ -13,12 +13,8 @@ use std::{
|
||||||
static AUX_DELEGATE_STATE_NAME: &str = "auxState";
|
static AUX_DELEGATE_STATE_NAME: &str = "auxState";
|
||||||
|
|
||||||
pub struct AuxDelegateState {
|
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 activation_policy: ActivationPolicy,
|
||||||
|
pub default_menu: bool,
|
||||||
pub create_default_menu: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppDelegateClass(pub *const Class);
|
pub struct AppDelegateClass(pub *const Class);
|
||||||
|
@ -54,11 +50,12 @@ extern "C" fn new(class: &Class, _: Sel) -> id {
|
||||||
unsafe {
|
unsafe {
|
||||||
let this: id = msg_send![class, alloc];
|
let this: id = msg_send![class, alloc];
|
||||||
let this: id = msg_send![this, init];
|
let this: id = msg_send![this, init];
|
||||||
|
// TODO: Remove the need for this initialization here
|
||||||
(*this).set_ivar(
|
(*this).set_ivar(
|
||||||
AUX_DELEGATE_STATE_NAME,
|
AUX_DELEGATE_STATE_NAME,
|
||||||
Box::into_raw(Box::new(RefCell::new(AuxDelegateState {
|
Box::into_raw(Box::new(RefCell::new(AuxDelegateState {
|
||||||
activation_policy: ActivationPolicy::Regular,
|
activation_policy: ActivationPolicy::Regular,
|
||||||
create_default_menu: true,
|
default_menu: true,
|
||||||
}))) as *mut c_void,
|
}))) as *mut c_void,
|
||||||
);
|
);
|
||||||
this
|
this
|
||||||
|
|
|
@ -296,7 +296,7 @@ impl AppState {
|
||||||
};
|
};
|
||||||
HANDLER.set_ready();
|
HANDLER.set_ready();
|
||||||
HANDLER.waker().start();
|
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 {
|
if create_default_menu {
|
||||||
// The menubar initialization should be before the `NewEvents` event, to allow
|
// The menubar initialization should be before the `NewEvents` event, to allow
|
||||||
// overriding of the default menu even if it's created
|
// 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();
|
let ns_app = NSApp();
|
||||||
// We need to delay setting the activation policy and activating the app
|
// We need to delay setting the activation policy and activating the app
|
||||||
// until `applicationDidFinishLaunching` has been called. Otherwise the
|
// 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;
|
let act_pol = get_aux_state_mut(app_delegate).activation_policy;
|
||||||
ns_app.setActivationPolicy_(match act_pol {
|
ns_app.setActivationPolicy_(match act_pol {
|
||||||
ActivationPolicy::Regular => NSApplicationActivationPolicyRegular,
|
ActivationPolicy::Regular => NSApplicationActivationPolicyRegular,
|
||||||
|
|
|
@ -22,7 +22,10 @@ use crate::{
|
||||||
event::Event,
|
event::Event,
|
||||||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootWindowTarget},
|
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootWindowTarget},
|
||||||
monitor::MonitorHandle as RootMonitorHandle,
|
monitor::MonitorHandle as RootMonitorHandle,
|
||||||
platform_impl::platform::{
|
platform::macos::ActivationPolicy,
|
||||||
|
platform_impl::{
|
||||||
|
get_aux_state_mut,
|
||||||
|
platform::{
|
||||||
app::APP_CLASS,
|
app::APP_CLASS,
|
||||||
app_delegate::APP_DELEGATE_CLASS,
|
app_delegate::APP_DELEGATE_CLASS,
|
||||||
app_state::{AppState, Callback},
|
app_state::{AppState, Callback},
|
||||||
|
@ -30,6 +33,7 @@ use crate::{
|
||||||
observer::*,
|
observer::*,
|
||||||
util::IdRef,
|
util::IdRef,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -100,7 +104,9 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
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>>,
|
window_target: Rc<RootWindowTarget<T>>,
|
||||||
panic_info: Rc<PanicInfo>,
|
panic_info: Rc<PanicInfo>,
|
||||||
|
@ -114,8 +120,23 @@ pub struct EventLoop<T: 'static> {
|
||||||
_callback: Option<Rc<Callback<T>>>,
|
_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> {
|
impl<T> EventLoop<T> {
|
||||||
pub fn new() -> Self {
|
pub(crate) fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||||
let delegate = unsafe {
|
let delegate = unsafe {
|
||||||
let is_main_thread: BOOL = msg_send!(class!(NSThread), isMainThread);
|
let is_main_thread: BOOL = msg_send!(class!(NSThread), isMainThread);
|
||||||
if is_main_thread == NO {
|
if is_main_thread == NO {
|
||||||
|
@ -129,15 +150,21 @@ impl<T> EventLoop<T> {
|
||||||
let app: id = msg_send![APP_CLASS.0, sharedApplication];
|
let app: id = msg_send![APP_CLASS.0, sharedApplication];
|
||||||
|
|
||||||
let delegate = IdRef::new(msg_send![APP_DELEGATE_CLASS.0, new]);
|
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(|| {
|
autoreleasepool(|| {
|
||||||
let _: () = msg_send![app, setDelegate:*delegate];
|
let _: () = msg_send![app, setDelegate:*delegate];
|
||||||
});
|
});
|
||||||
|
|
||||||
delegate
|
delegate
|
||||||
};
|
};
|
||||||
let panic_info: Rc<PanicInfo> = Default::default();
|
let panic_info: Rc<PanicInfo> = Default::default();
|
||||||
setup_control_flow_observers(Rc::downgrade(&panic_info));
|
setup_control_flow_observers(Rc::downgrade(&panic_info));
|
||||||
EventLoop {
|
EventLoop {
|
||||||
delegate,
|
_delegate: delegate,
|
||||||
window_target: Rc::new(RootWindowTarget {
|
window_target: Rc::new(RootWindowTarget {
|
||||||
p: Default::default(),
|
p: Default::default(),
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
|
|
|
@ -18,9 +18,12 @@ mod window_delegate;
|
||||||
|
|
||||||
use std::{fmt, ops::Deref, sync::Arc};
|
use std::{fmt, ops::Deref, sync::Arc};
|
||||||
|
|
||||||
pub use self::{
|
pub(crate) use self::{
|
||||||
app_delegate::{get_aux_state_mut, AuxDelegateState},
|
app_delegate::get_aux_state_mut,
|
||||||
event_loop::{EventLoop, EventLoopWindowTarget, Proxy as EventLoopProxy},
|
event_loop::{
|
||||||
|
EventLoop, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes,
|
||||||
|
Proxy as EventLoopProxy,
|
||||||
|
},
|
||||||
monitor::{MonitorHandle, VideoMode},
|
monitor::{MonitorHandle, VideoMode},
|
||||||
window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, UnownedWindow},
|
window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, UnownedWindow},
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,8 +16,11 @@ pub struct EventLoop<T: 'static> {
|
||||||
elw: root::EventLoopWindowTarget<T>,
|
elw: root::EventLoopWindowTarget<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Hash)]
|
||||||
|
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||||
|
|
||||||
impl<T> EventLoop<T> {
|
impl<T> EventLoop<T> {
|
||||||
pub fn new() -> Self {
|
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||||
EventLoop {
|
EventLoop {
|
||||||
elw: root::EventLoopWindowTarget {
|
elw: root::EventLoopWindowTarget {
|
||||||
p: WindowTarget::new(),
|
p: WindowTarget::new(),
|
||||||
|
|
|
@ -28,8 +28,9 @@ mod backend;
|
||||||
|
|
||||||
pub use self::device::Id as DeviceId;
|
pub use self::device::Id as DeviceId;
|
||||||
pub use self::error::OsError;
|
pub use self::error::OsError;
|
||||||
pub use self::event_loop::{
|
pub(crate) use self::event_loop::{
|
||||||
EventLoop, Proxy as EventLoopProxy, WindowTarget as EventLoopWindowTarget,
|
EventLoop, PlatformSpecificEventLoopAttributes, Proxy as EventLoopProxy,
|
||||||
|
WindowTarget as EventLoopWindowTarget,
|
||||||
};
|
};
|
||||||
pub use self::monitor::{Handle as MonitorHandle, Mode as VideoMode};
|
pub use self::monitor::{Handle as MonitorHandle, Mode as VideoMode};
|
||||||
pub use self::window::{
|
pub use self::window::{
|
||||||
|
|
|
@ -113,48 +113,44 @@ pub struct EventLoop<T: 'static> {
|
||||||
window_target: RootELW<T>,
|
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> {
|
pub struct EventLoopWindowTarget<T: 'static> {
|
||||||
thread_id: DWORD,
|
thread_id: DWORD,
|
||||||
thread_msg_target: HWND,
|
thread_msg_target: HWND,
|
||||||
pub(crate) runner_shared: EventLoopRunnerShared<T>,
|
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> {
|
impl<T: 'static> EventLoop<T> {
|
||||||
pub fn new() -> EventLoop<T> {
|
pub(crate) fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Self {
|
||||||
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> {
|
|
||||||
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
|
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 thread_msg_target = create_event_target_window::<T>();
|
||||||
|
|
||||||
let send_thread_msg_target = thread_msg_target as usize;
|
let send_thread_msg_target = thread_msg_target as usize;
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
use winapi::{self, shared::windef::HMENU, shared::windef::HWND};
|
use winapi::{self, shared::windef::HMENU, shared::windef::HWND};
|
||||||
|
|
||||||
pub use self::{
|
pub(crate) use self::{
|
||||||
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
|
event_loop::{
|
||||||
|
EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes,
|
||||||
|
},
|
||||||
icon::WinIcon,
|
icon::WinIcon,
|
||||||
monitor::{MonitorHandle, VideoMode},
|
monitor::{MonitorHandle, VideoMode},
|
||||||
window::Window,
|
window::Window,
|
||||||
|
|
|
@ -83,7 +83,7 @@ impl WindowId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Object that allows you to build windows.
|
/// Object that allows building windows.
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct WindowBuilder {
|
pub struct WindowBuilder {
|
||||||
/// The attributes to use to create the window.
|
/// The attributes to use to create the window.
|
||||||
|
|
Loading…
Reference in a new issue