Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 57 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1620,6 +1620,26 @@ dependencies = [
"pin-project-lite",
]

[[package]]
name = "external_eventloop"
version = "0.1.0"
dependencies = [
"eframe",
"env_logger",
"winit",
]

[[package]]
name = "external_eventloop_async"
version = "0.1.0"
dependencies = [
"eframe",
"env_logger",
"log",
"tokio",
"winit",
]

[[package]]
name = "fancy-regex"
version = "0.11.0"
Expand Down Expand Up @@ -2452,9 +2472,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"

[[package]]
name = "libc"
version = "0.2.161"
version = "0.2.168"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"

[[package]]
name = "libloading"
Expand Down Expand Up @@ -2609,6 +2629,17 @@ version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"

[[package]]
name = "mio"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0",
]

[[package]]
name = "multiple_viewports"
version = "0.1.0"
Expand Down Expand Up @@ -3865,6 +3896,16 @@ dependencies = [
"serde",
]

[[package]]
name = "socket2"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
dependencies = [
"libc",
"windows-sys 0.52.0",
]

[[package]]
name = "spirv"
version = "0.3.0+sdk-1.3.268.0"
Expand Down Expand Up @@ -4183,6 +4224,20 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"

[[package]]
name = "tokio"
version = "1.44.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
dependencies = [
"backtrace",
"libc",
"mio",
"pin-project-lite",
"socket2",
"windows-sys 0.52.0",
]

[[package]]
name = "toml_datetime"
version = "0.6.8"
Expand Down
124 changes: 110 additions & 14 deletions crates/eframe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,14 @@ pub use web::{WebLogger, WebRunner};
#[cfg(any(feature = "glow", feature = "wgpu"))]
mod native;

#[cfg(not(target_arch = "wasm32"))]
#[cfg(any(feature = "glow", feature = "wgpu"))]
pub use native::run::EframeWinitApplication;

#[cfg(not(any(target_arch = "wasm32", target_os = "ios")))]
#[cfg(any(feature = "glow", feature = "wgpu"))]
pub use native::run::EframePumpStatus;

#[cfg(not(target_arch = "wasm32"))]
#[cfg(any(feature = "glow", feature = "wgpu"))]
#[cfg(feature = "persistence")]
Expand Down Expand Up @@ -242,6 +250,106 @@ pub fn run_native(
mut native_options: NativeOptions,
app_creator: AppCreator<'_>,
) -> Result {
let renderer = init_native(app_name, &mut native_options);

match renderer {
#[cfg(feature = "glow")]
Renderer::Glow => {
log::debug!("Using the glow renderer");
native::run::run_glow(app_name, native_options, app_creator)
}

#[cfg(feature = "wgpu")]
Renderer::Wgpu => {
log::debug!("Using the wgpu renderer");
native::run::run_wgpu(app_name, native_options, app_creator)
}
}
}

/// Provides a proxy for your native eframe application to run on your own event loop.
///
/// See `run_native` for details about `app_name`.
///
/// Call from `fn main` like this:
/// ``` no_run
/// use eframe::{egui, UserEvent};
/// use winit::event_loop::{ControlFlow, EventLoop};
///
/// fn main() -> eframe::Result {
/// let native_options = eframe::NativeOptions::default();
/// let eventloop = EventLoop::<UserEvent>::with_user_event().build()?;
/// eventloop.set_control_flow(ControlFlow::Poll);
///
/// let mut winit_app = eframe::create_native(
/// "MyExtApp",
/// native_options,
/// Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc)))),
/// &eventloop,
/// );
///
/// eventloop.run_app(&mut winit_app)?;
///
/// Ok(())
/// }
///
/// #[derive(Default)]
/// struct MyEguiApp {}
///
/// impl MyEguiApp {
/// fn new(cc: &eframe::CreationContext<'_>) -> Self {
/// Self::default()
/// }
/// }
///
/// impl eframe::App for MyEguiApp {
/// fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
/// egui::CentralPanel::default().show(ctx, |ui| {
/// ui.heading("Hello World!");
/// });
/// }
/// }
/// ```
///
/// See the `external_eventloop` example for a more complete example.
#[cfg(not(target_arch = "wasm32"))]
#[cfg(any(feature = "glow", feature = "wgpu"))]
pub fn create_native<'a>(
app_name: &str,
mut native_options: NativeOptions,
app_creator: AppCreator<'a>,
event_loop: &winit::event_loop::EventLoop<UserEvent>,
) -> EframeWinitApplication<'a> {
let renderer = init_native(app_name, &mut native_options);

match renderer {
#[cfg(feature = "glow")]
Renderer::Glow => {
log::debug!("Using the glow renderer");
EframeWinitApplication::new(native::run::create_glow(
app_name,
native_options,
app_creator,
event_loop,
))
}

#[cfg(feature = "wgpu")]
Renderer::Wgpu => {
log::debug!("Using the wgpu renderer");
EframeWinitApplication::new(native::run::create_wgpu(
app_name,
native_options,
app_creator,
event_loop,
))
}
}
}

#[cfg(not(target_arch = "wasm32"))]
#[cfg(any(feature = "glow", feature = "wgpu"))]
fn init_native(app_name: &str, native_options: &mut NativeOptions) -> Renderer {
#[cfg(not(feature = "__screenshot"))]
assert!(
std::env::var("EFRAME_SCREENSHOT_TO").is_err(),
Expand All @@ -256,26 +364,14 @@ pub fn run_native(

#[cfg(all(feature = "glow", feature = "wgpu"))]
{
match renderer {
match native_options.renderer {
Renderer::Glow => "glow",
Renderer::Wgpu => "wgpu",
};
log::info!("Both the glow and wgpu renderers are available. Using {renderer}.");
}

match renderer {
#[cfg(feature = "glow")]
Renderer::Glow => {
log::debug!("Using the glow renderer");
native::run::run_glow(app_name, native_options, app_creator)
}

#[cfg(feature = "wgpu")]
Renderer::Wgpu => {
log::debug!("Using the wgpu renderer");
native::run::run_wgpu(app_name, native_options, app_creator)
}
}
renderer
}

// ----------------------------------------------------------------------------
Expand Down
130 changes: 130 additions & 0 deletions crates/eframe/src/native/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,19 @@ pub fn run_glow(
run_and_exit(event_loop, glow_eframe)
}

#[cfg(feature = "glow")]
pub fn create_glow<'a>(
app_name: &str,
native_options: epi::NativeOptions,
app_creator: epi::AppCreator<'a>,
event_loop: &EventLoop<UserEvent>,
) -> impl ApplicationHandler<UserEvent> + 'a {
use super::glow_integration::GlowWinitApp;

let glow_eframe = GlowWinitApp::new(event_loop, app_name, native_options, app_creator);
WinitAppWrapper::new(glow_eframe, true)
}

// ----------------------------------------------------------------------------

#[cfg(feature = "wgpu")]
Expand All @@ -386,3 +399,120 @@ pub fn run_wgpu(
let wgpu_eframe = WgpuWinitApp::new(&event_loop, app_name, native_options, app_creator);
run_and_exit(event_loop, wgpu_eframe)
}

#[cfg(feature = "wgpu")]
pub fn create_wgpu<'a>(
app_name: &str,
native_options: epi::NativeOptions,
app_creator: epi::AppCreator<'a>,
event_loop: &EventLoop<UserEvent>,
) -> impl ApplicationHandler<UserEvent> + 'a {
use super::wgpu_integration::WgpuWinitApp;

let wgpu_eframe = WgpuWinitApp::new(event_loop, app_name, native_options, app_creator);
WinitAppWrapper::new(wgpu_eframe, true)
}

// ----------------------------------------------------------------------------

/// A proxy to the eframe application that implements [`ApplicationHandler`].
///
/// This can be run directly on your own [`EventLoop`] by itself or with other
/// windows you manage outside of eframe.
pub struct EframeWinitApplication<'a> {
wrapper: Box<dyn ApplicationHandler<UserEvent> + 'a>,
control_flow: ControlFlow,
}

impl ApplicationHandler<UserEvent> for EframeWinitApplication<'_> {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
self.wrapper.resumed(event_loop);
}

fn window_event(
&mut self,
event_loop: &ActiveEventLoop,
window_id: winit::window::WindowId,
event: winit::event::WindowEvent,
) {
self.wrapper.window_event(event_loop, window_id, event);
}

fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: winit::event::StartCause) {
self.wrapper.new_events(event_loop, cause);
}

fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) {
self.wrapper.user_event(event_loop, event);
}

fn device_event(
&mut self,
event_loop: &ActiveEventLoop,
device_id: winit::event::DeviceId,
event: winit::event::DeviceEvent,
) {
self.wrapper.device_event(event_loop, device_id, event);
}

fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
self.wrapper.about_to_wait(event_loop);
self.control_flow = event_loop.control_flow();
}

fn suspended(&mut self, event_loop: &ActiveEventLoop) {
self.wrapper.suspended(event_loop);
}

fn exiting(&mut self, event_loop: &ActiveEventLoop) {
self.wrapper.exiting(event_loop);
}

fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
self.wrapper.memory_warning(event_loop);
}
}

impl<'a> EframeWinitApplication<'a> {
pub(crate) fn new<T: ApplicationHandler<UserEvent> + 'a>(app: T) -> Self {
Self {
wrapper: Box::new(app),
control_flow: ControlFlow::default(),
}
}

/// Pump the `EventLoop` to check for and dispatch pending events to this application.
///
/// Returns either the exit code for the application or the final state of the [`ControlFlow`]
/// after all events have been dispatched in this iteration.
///
/// This is useful when your [`EventLoop`] is not the main event loop for your application.
/// See the `external_eventloop_async` example.
#[cfg(not(target_os = "ios"))]
pub fn pump_eframe_app(
&mut self,
event_loop: &mut EventLoop<UserEvent>,
timeout: Option<std::time::Duration>,
) -> EframePumpStatus {
use winit::platform::pump_events::{EventLoopExtPumpEvents as _, PumpStatus};

match event_loop.pump_app_events(timeout, self) {
PumpStatus::Continue => EframePumpStatus::Continue(self.control_flow),
PumpStatus::Exit(code) => EframePumpStatus::Exit(code),
}
}
}

/// Either an exit code or a [`ControlFlow`] from the [`ActiveEventLoop`].
///
/// The result of [`EframeWinitApplication::pump_eframe_app`].
#[cfg(not(target_os = "ios"))]
pub enum EframePumpStatus {
/// The final state of the [`ControlFlow`] after all events have been dispatched
///
/// Callers should perform the action that is appropriate for the [`ControlFlow`] value.
Continue(ControlFlow),

/// The exit code for the application
Exit(i32),
}
Loading