From 7475a565dc83cb7a1ca5081eb862bfa4a51a4efd Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 15 Aug 2022 14:05:17 +0200 Subject: [PATCH 1/5] Add example of opening several eframe windows in series --- Cargo.lock | 7 +++++ Cargo.toml | 14 +-------- examples/serial_windows/Cargo.toml | 12 ++++++++ examples/serial_windows/README.md | 5 ++++ examples/serial_windows/src/main.rs | 45 +++++++++++++++++++++++++++++ 5 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 examples/serial_windows/Cargo.toml create mode 100644 examples/serial_windows/README.md create mode 100644 examples/serial_windows/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index d6e25b668617..7c779ccdd6db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3438,6 +3438,13 @@ dependencies = [ "syn", ] +[[package]] +name = "serial_windows" +version = "0.1.0" +dependencies = [ + "eframe", +] + [[package]] name = "servo-fontconfig" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index b05a4925b3fb..8dd656f77ed3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,19 +12,7 @@ members = [ "emath", "epaint", - "examples/confirm_exit", - "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", + "examples/*", ] [profile.dev] diff --git a/examples/serial_windows/Cargo.toml b/examples/serial_windows/Cargo.toml new file mode 100644 index 000000000000..a73860800592 --- /dev/null +++ b/examples/serial_windows/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "serial_windows" +version = "0.1.0" +authors = ["Emil Ernerfeldt "] +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.61" +publish = false + + +[dependencies] +eframe = { path = "../../eframe" } diff --git a/examples/serial_windows/README.md b/examples/serial_windows/README.md new file mode 100644 index 000000000000..c3700e638ce4 --- /dev/null +++ b/examples/serial_windows/README.md @@ -0,0 +1,5 @@ +Demonstrates how to open several windows after each other. + +```sh +cargo run -p serial_windows +``` diff --git a/examples/serial_windows/src/main.rs b/examples/serial_windows/src/main.rs new file mode 100644 index 000000000000..6b622a98c0fa --- /dev/null +++ b/examples/serial_windows/src/main.rs @@ -0,0 +1,45 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + +use eframe::egui; + +fn main() { + let options = eframe::NativeOptions { + run_and_return: true, + ..Default::default() + }; + + eframe::run_native( + "First Window", + options.clone(), + Box::new(|_cc| Box::new(MyApp::default())), + ); + + std::thread::sleep(std::time::Duration::from_secs(2)); + + eframe::run_native( + "Second Window", + options.clone(), + Box::new(|_cc| Box::new(MyApp::default())), + ); + + std::thread::sleep(std::time::Duration::from_secs(2)); + + 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() { + frame.quit(); + } + }); + } +} From 3f8f93b55754c154acbfcd3dbbc7436eff7c7686 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 15 Aug 2022 14:05:29 +0200 Subject: [PATCH 2/5] Reuse the same winit event loop --- eframe/src/native/run.rs | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/eframe/src/native/run.rs b/eframe/src/native/run.rs index b67271a6e421..680b4d66a605 100644 --- a/eframe/src/native/run.rs +++ b/eframe/src/native/run.rs @@ -72,7 +72,20 @@ trait WinitApp { fn on_event(&mut self, event: winit::event::Event<'_, RequestRepaintEvent>) -> EventResult; } -fn run_and_return(mut event_loop: EventLoop, 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)) { + use std::cell::RefCell; + thread_local!(static EVENT_LOOP: RefCell> = 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, mut winit_app: impl WinitApp) { use winit::platform::run_return::EventLoopExtRunReturn as _; tracing::debug!("event_loop.run_return"); @@ -424,12 +437,15 @@ mod glow_integration { native_options: &epi::NativeOptions, 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 { - 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 { + 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); } } @@ -684,12 +700,15 @@ mod wgpu_integration { native_options: &epi::NativeOptions, 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 { - 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 { + 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); } } From fff5b39c9dc3a334d0dea076da1230a57f209a1c Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 15 Aug 2022 15:41:12 +0200 Subject: [PATCH 3/5] Ignore events to the wrong window --- eframe/src/native/run.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/eframe/src/native/run.rs b/eframe/src/native/run.rs index 680b4d66a605..3319c86506fe 100644 --- a/eframe/src/native/run.rs +++ b/eframe/src/native/run.rs @@ -113,6 +113,14 @@ fn run_and_return(event_loop: &mut EventLoop, mut winit_app .. }) => 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), }; From c9664a1051164a74b592e6e0a56655c64ea4f17d Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 15 Aug 2022 15:43:12 +0200 Subject: [PATCH 4/5] Run run_return again --- eframe/src/native/run.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/eframe/src/native/run.rs b/eframe/src/native/run.rs index 3319c86506fe..217d2f720837 100644 --- a/eframe/src/native/run.rs +++ b/eframe/src/native/run.rs @@ -152,6 +152,13 @@ fn run_and_return(event_loop: &mut EventLoop, mut winit_app tracing::debug!("eframe window closed"); 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( From 588e0e768e3a03e99da6759401b1555e41d09a81 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 15 Aug 2022 16:29:27 +0200 Subject: [PATCH 5/5] Add warning about the example not working on Mac --- examples/serial_windows/README.md | 3 +++ examples/serial_windows/src/main.rs | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/examples/serial_windows/README.md b/examples/serial_windows/README.md index c3700e638ce4..4941ce2702a6 100644 --- a/examples/serial_windows/README.md +++ b/examples/serial_windows/README.md @@ -1,5 +1,8 @@ Demonstrates how to open several windows after each other. +NOTE: this doesn't work on Mac due to . +See also . + ```sh cargo run -p serial_windows ``` diff --git a/examples/serial_windows/src/main.rs b/examples/serial_windows/src/main.rs index 6b622a98c0fa..79362ca16fbc 100644 --- a/examples/serial_windows/src/main.rs +++ b/examples/serial_windows/src/main.rs @@ -3,11 +3,16 @@ 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(), @@ -16,6 +21,7 @@ fn main() { std::thread::sleep(std::time::Duration::from_secs(2)); + eprintln!("Starting second window…"); eframe::run_native( "Second Window", options.clone(), @@ -24,6 +30,7 @@ fn main() { std::thread::sleep(std::time::Duration::from_secs(2)); + eprintln!("Starting third window…"); eframe::run_native( "Third Window", options, @@ -38,6 +45,7 @@ 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(); } });