eframe: several windows in series (#1919)
* Add example of opening several eframe windows in series * Reuse the same winit event loop * Ignore events to the wrong window * Run run_return again
This commit is contained in:
parent
48e7f219a3
commit
9c58f12a6c
6 changed files with 124 additions and 22 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -3438,6 +3438,13 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_windows"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"eframe",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo-fontconfig"
|
name = "servo-fontconfig"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
14
Cargo.toml
14
Cargo.toml
|
@ -12,19 +12,7 @@ members = [
|
||||||
"emath",
|
"emath",
|
||||||
"epaint",
|
"epaint",
|
||||||
|
|
||||||
"examples/confirm_exit",
|
"examples/*",
|
||||||
"examples/custom_3d_glow",
|
|
||||||
"examples/custom_3d_three-d",
|
|
||||||
"examples/custom_font",
|
|
||||||
"examples/custom_font_style",
|
|
||||||
"examples/custom_window_frame",
|
|
||||||
"examples/download_image",
|
|
||||||
"examples/file_dialog",
|
|
||||||
"examples/hello_world",
|
|
||||||
"examples/puffin_profiler",
|
|
||||||
"examples/retained_image",
|
|
||||||
"examples/screenshot",
|
|
||||||
"examples/svg",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|
|
@ -72,7 +72,20 @@ trait WinitApp {
|
||||||
fn on_event(&mut self, event: winit::event::Event<'_, RequestRepaintEvent>) -> EventResult;
|
fn on_event(&mut self, event: winit::event::Event<'_, RequestRepaintEvent>) -> EventResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_and_return(mut event_loop: EventLoop<RequestRepaintEvent>, mut winit_app: impl WinitApp) {
|
/// Access a thread-local event loop.
|
||||||
|
///
|
||||||
|
/// We reuse the event-loop so we can support closing and opening an eframe window
|
||||||
|
/// multiple times. This is just a limitation of winit.
|
||||||
|
fn with_event_loop(f: impl FnOnce(&mut EventLoop<RequestRepaintEvent>)) {
|
||||||
|
use std::cell::RefCell;
|
||||||
|
thread_local!(static EVENT_LOOP: RefCell<EventLoop<RequestRepaintEvent>> = RefCell::new(winit::event_loop::EventLoopBuilder::with_user_event().build()));
|
||||||
|
|
||||||
|
EVENT_LOOP.with(|event_loop| {
|
||||||
|
f(&mut *event_loop.borrow_mut());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_and_return(event_loop: &mut EventLoop<RequestRepaintEvent>, mut winit_app: impl WinitApp) {
|
||||||
use winit::platform::run_return::EventLoopExtRunReturn as _;
|
use winit::platform::run_return::EventLoopExtRunReturn as _;
|
||||||
|
|
||||||
tracing::debug!("event_loop.run_return");
|
tracing::debug!("event_loop.run_return");
|
||||||
|
@ -100,6 +113,14 @@ fn run_and_return(mut event_loop: EventLoop<RequestRepaintEvent>, mut winit_app:
|
||||||
..
|
..
|
||||||
}) => EventResult::RepaintAsap,
|
}) => EventResult::RepaintAsap,
|
||||||
|
|
||||||
|
winit::event::Event::WindowEvent { window_id, .. }
|
||||||
|
if window_id != winit_app.window().id() =>
|
||||||
|
{
|
||||||
|
// This can happen if we close a window, and then reopen a new one,
|
||||||
|
// or if we have multiple windows open.
|
||||||
|
EventResult::Wait
|
||||||
|
}
|
||||||
|
|
||||||
event => winit_app.on_event(event),
|
event => winit_app.on_event(event),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,6 +152,13 @@ fn run_and_return(mut event_loop: EventLoop<RequestRepaintEvent>, mut winit_app:
|
||||||
tracing::debug!("eframe window closed");
|
tracing::debug!("eframe window closed");
|
||||||
|
|
||||||
winit_app.save_and_destroy();
|
winit_app.save_and_destroy();
|
||||||
|
|
||||||
|
drop(winit_app);
|
||||||
|
|
||||||
|
// Needed to clean the event_loop:
|
||||||
|
event_loop.run_return(|_, _, control_flow| {
|
||||||
|
control_flow.set_exit();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_and_exit(
|
fn run_and_exit(
|
||||||
|
@ -424,12 +452,15 @@ mod glow_integration {
|
||||||
native_options: &epi::NativeOptions,
|
native_options: &epi::NativeOptions,
|
||||||
app_creator: epi::AppCreator,
|
app_creator: epi::AppCreator,
|
||||||
) {
|
) {
|
||||||
let event_loop = glutin::event_loop::EventLoopBuilder::with_user_event().build();
|
|
||||||
let glow_eframe = GlowWinitApp::new(&event_loop, app_name, native_options, app_creator);
|
|
||||||
|
|
||||||
if native_options.run_and_return {
|
if native_options.run_and_return {
|
||||||
run_and_return(event_loop, glow_eframe);
|
with_event_loop(|event_loop| {
|
||||||
|
let glow_eframe =
|
||||||
|
GlowWinitApp::new(event_loop, app_name, native_options, app_creator);
|
||||||
|
run_and_return(event_loop, glow_eframe);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
|
let event_loop = winit::event_loop::EventLoopBuilder::with_user_event().build();
|
||||||
|
let glow_eframe = GlowWinitApp::new(&event_loop, app_name, native_options, app_creator);
|
||||||
run_and_exit(event_loop, glow_eframe);
|
run_and_exit(event_loop, glow_eframe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -684,12 +715,15 @@ mod wgpu_integration {
|
||||||
native_options: &epi::NativeOptions,
|
native_options: &epi::NativeOptions,
|
||||||
app_creator: epi::AppCreator,
|
app_creator: epi::AppCreator,
|
||||||
) {
|
) {
|
||||||
let event_loop = winit::event_loop::EventLoopBuilder::with_user_event().build();
|
|
||||||
let wgpu_eframe = WgpuWinitApp::new(&event_loop, app_name, native_options, app_creator);
|
|
||||||
|
|
||||||
if native_options.run_and_return {
|
if native_options.run_and_return {
|
||||||
run_and_return(event_loop, wgpu_eframe);
|
with_event_loop(|event_loop| {
|
||||||
|
let wgpu_eframe =
|
||||||
|
WgpuWinitApp::new(event_loop, app_name, native_options, app_creator);
|
||||||
|
run_and_return(event_loop, wgpu_eframe);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
|
let event_loop = winit::event_loop::EventLoopBuilder::with_user_event().build();
|
||||||
|
let wgpu_eframe = WgpuWinitApp::new(&event_loop, app_name, native_options, app_creator);
|
||||||
run_and_exit(event_loop, wgpu_eframe);
|
run_and_exit(event_loop, wgpu_eframe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
examples/serial_windows/Cargo.toml
Normal file
12
examples/serial_windows/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "serial_windows"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.61"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
eframe = { path = "../../eframe" }
|
8
examples/serial_windows/README.md
Normal file
8
examples/serial_windows/README.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Demonstrates how to open several windows after each other.
|
||||||
|
|
||||||
|
NOTE: this doesn't work on Mac due to <https://github.com/rust-windowing/winit/issues/2431>.
|
||||||
|
See also <https://github.com/emilk/egui/issues/1918>.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo run -p serial_windows
|
||||||
|
```
|
53
examples/serial_windows/src/main.rs
Normal file
53
examples/serial_windows/src/main.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
|
use eframe::egui;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
eprintln!("WARNING: this example does not work on Mac! See https://github.com/emilk/egui/issues/1918");
|
||||||
|
}
|
||||||
|
|
||||||
|
let options = eframe::NativeOptions {
|
||||||
|
run_and_return: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
eprintln!("Starting first window…");
|
||||||
|
eframe::run_native(
|
||||||
|
"First Window",
|
||||||
|
options.clone(),
|
||||||
|
Box::new(|_cc| Box::new(MyApp::default())),
|
||||||
|
);
|
||||||
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||||
|
|
||||||
|
eprintln!("Starting second window…");
|
||||||
|
eframe::run_native(
|
||||||
|
"Second Window",
|
||||||
|
options.clone(),
|
||||||
|
Box::new(|_cc| Box::new(MyApp::default())),
|
||||||
|
);
|
||||||
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||||
|
|
||||||
|
eprintln!("Starting third window…");
|
||||||
|
eframe::run_native(
|
||||||
|
"Third Window",
|
||||||
|
options,
|
||||||
|
Box::new(|_cc| Box::new(MyApp::default())),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct MyApp {}
|
||||||
|
|
||||||
|
impl eframe::App for MyApp {
|
||||||
|
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
|
if ui.button("Close").clicked() {
|
||||||
|
eprintln!("Pressed Close button");
|
||||||
|
frame.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue