From 3e1db880dcba1db061e0b0208d73fce22896d055 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 30 Sep 2021 18:53:41 +0200 Subject: [PATCH] Revert change to winit event loop in egui_glium (#756) * Revert change to winit event loop in egui_glium This reverts https://github.com/emilk/egui/pull/631 Fixes https://github.com/emilk/egui/issues/755 * Add example of file dialogs and file drag-and-drop * fix ci --- .github/workflows/rust.yml | 4 +- Cargo.lock | 214 +++++++++++++++++++++++++++++++++ eframe/CHANGELOG.md | 2 + eframe/Cargo.toml | 1 + eframe/examples/file_dialog.rs | 100 +++++++++++++++ eframe/src/lib.rs | 2 +- egui_glium/CHANGELOG.md | 2 +- egui_glium/src/backend.rs | 140 +++++++++------------ 8 files changed, 377 insertions(+), 88 deletions(-) create mode 100644 eframe/examples/file_dialog.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 56bb1ad7..d7d07674 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -82,7 +82,7 @@ jobs: profile: minimal toolchain: 1.54.0 override: true - - run: sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libssl-dev + - run: sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libssl-dev libgtk-3-dev # libgtk-3-dev is used by rfd - uses: actions-rs/cargo@v1 with: command: test @@ -115,7 +115,7 @@ jobs: toolchain: 1.54.0 override: true - run: rustup component add clippy - - run: sudo apt-get install libspeechd-dev + - run: sudo apt-get install libspeechd-dev libgtk-3-dev # libgtk-3-dev is used by rfd - uses: actions-rs/cargo@v1 with: command: clippy diff --git a/Cargo.lock b/Cargo.lock index bfac54a0..e39da544 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "ab_glyph" version = "0.2.11" @@ -85,6 +87,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "anyhow" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" + +[[package]] +name = "atk-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "badcf670157c84bb8b1cf6b5f70b650fed78da2033c9eed84c4e49b11cbe83ea" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "atomic_refcell" version = "0.1.7" @@ -236,6 +256,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +[[package]] +name = "cairo-sys-rs" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c9c3928781e8a017ece15eace05230f04b647457d170d2d9641c94a444ff80" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "calloop" version = "0.6.5" @@ -276,6 +306,15 @@ dependencies = [ "nom 6.2.1", ] +[[package]] +name = "cfg-expr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e" +dependencies = [ + "smallvec", +] + [[package]] name = "cfg-if" version = "0.1.10" @@ -785,6 +824,7 @@ dependencies = [ "egui_web", "epi", "image", + "rfd", ] [[package]] @@ -989,6 +1029,36 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +[[package]] +name = "gdk-pixbuf-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f097c0704201fbc8f69c1762dc58c6947c8bb188b8ed0bc7e65259f1894fe590" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e091b3d3d6696949ac3b3fb3c62090e5bfd7bd6850bef5c3c5ea701de1b1f1e" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + [[package]] name = "getrandom" version = "0.2.3" @@ -1006,6 +1076,19 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" +[[package]] +name = "gio-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + [[package]] name = "gl_generator" version = "0.14.0" @@ -1017,6 +1100,16 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "glib-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "glium" version = "0.30.2" @@ -1111,6 +1204,35 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "gobject-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c14c8d3da0545785a7c5a120345b3abb534010fb8ae0f2ef3f47c027fba303e" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + [[package]] name = "half" version = "1.7.1" @@ -1123,6 +1245,15 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1700,6 +1831,18 @@ dependencies = [ "ttf-parser 0.12.3", ] +[[package]] +name = "pango-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2367099ca5e761546ba1d501955079f097caa186bb53ce0f718dca99ac1942fe" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -1916,6 +2059,29 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "rfd" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b4745feef3bc92e709042c78d205e9a566ec46e18c58d4fac458e6fc12627e" +dependencies = [ + "block", + "dispatch", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "lazy_static", + "objc", + "objc-foundation", + "objc_id", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winapi", +] + [[package]] name = "ring" version = "0.16.20" @@ -2182,6 +2348,24 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" +[[package]] +name = "strum" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" + +[[package]] +name = "strum_macros" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syn" version = "1.0.77" @@ -2215,6 +2399,24 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "system-deps" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6" +dependencies = [ + "anyhow", + "cfg-expr", + "heck", + "itertools", + "pkg-config", + "strum", + "strum_macros", + "thiserror", + "toml", + "version-compare", +] + [[package]] name = "takeable-option" version = "0.5.0" @@ -2357,6 +2559,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + [[package]] name = "unicode-width" version = "0.1.9" @@ -2415,6 +2623,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "version-compare" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" + [[package]] name = "version_check" version = "0.9.3" diff --git a/eframe/CHANGELOG.md b/eframe/CHANGELOG.md index 8d870e29..cbe9bea7 100644 --- a/eframe/CHANGELOG.md +++ b/eframe/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog for eframe All notable changes to the `eframe` and `epi` crates. +NOTE: [`egui_web`](egui_web/CHANGELOG.md), [`egui-winit`](egui-winit/CHANGELOG.md) and [`egui_glium`](egui_glium/CHANGELOG.md) have their own changelogs! + ## Unreleased * `Frame` now provides `set_decorations` to set whether to show window decorations. diff --git a/eframe/Cargo.toml b/eframe/Cargo.toml index 9f9b7fae..fcc12277 100644 --- a/eframe/Cargo.toml +++ b/eframe/Cargo.toml @@ -36,6 +36,7 @@ egui_web = { version = "0.14.0", path = "../egui_web", default-features = false [dev-dependencies] image = { version = "0.23", default-features = false, features = ["png"] } +rfd = "0.5.0" [features] default = ["default_fonts"] diff --git a/eframe/examples/file_dialog.rs b/eframe/examples/file_dialog.rs new file mode 100644 index 00000000..91585c4f --- /dev/null +++ b/eframe/examples/file_dialog.rs @@ -0,0 +1,100 @@ +use eframe::{egui, epi}; + +#[derive(Default)] +struct MyApp { + dropped_files: Vec, + picked_path: Option, +} + +impl epi::App for MyApp { + fn name(&self) -> &str { + "Native file dialogs and drag-and-drop files" + } + + fn update(&mut self, ctx: &egui::CtxRef, _frame: &mut epi::Frame<'_>) { + egui::CentralPanel::default().show(ctx, |ui| { + ui.label("Drag-and-drop files onto the window!"); + + if cfg!(target_os = "macos") { + // Awaiting fix of winit bug: https://github.com/rust-windowing/winit/pull/2027 + } else if ui.button("Open file…").clicked() { + if let Some(path) = rfd::FileDialog::new().pick_file() { + self.picked_path = Some(path.display().to_string()); + } + } + + if let Some(picked_path) = &self.picked_path { + ui.horizontal(|ui| { + ui.label("Picked file:"); + ui.monospace(picked_path); + }); + } + + // Show dropped files (if any): + if !self.dropped_files.is_empty() { + ui.group(|ui| { + ui.label("Dropped files:"); + + for file in &self.dropped_files { + let mut info = if let Some(path) = &file.path { + path.display().to_string() + } else if !file.name.is_empty() { + file.name.clone() + } else { + "???".to_owned() + }; + if let Some(bytes) = &file.bytes { + info += &format!(" ({} bytes)", bytes.len()); + } + ui.label(info); + } + }); + } + }); + + self.detect_files_being_dropped(ctx); + } +} + +impl MyApp { + fn detect_files_being_dropped(&mut self, ctx: &egui::CtxRef) { + use egui::*; + + // Preview hovering files: + if !ctx.input().raw.hovered_files.is_empty() { + let mut text = "Dropping files:\n".to_owned(); + for file in &ctx.input().raw.hovered_files { + if let Some(path) = &file.path { + text += &format!("\n{}", path.display()); + } else if !file.mime.is_empty() { + text += &format!("\n{}", file.mime); + } else { + text += "\n???"; + } + } + + let painter = + ctx.layer_painter(LayerId::new(Order::Foreground, Id::new("file_drop_target"))); + + let screen_rect = ctx.input().screen_rect(); + painter.rect_filled(screen_rect, 0.0, Color32::from_black_alpha(192)); + painter.text( + screen_rect.center(), + Align2::CENTER_CENTER, + text, + TextStyle::Heading, + Color32::WHITE, + ); + } + + // Collect dropped files: + if !ctx.input().raw.dropped_files.is_empty() { + self.dropped_files = ctx.input().raw.dropped_files.clone(); + } + } +} + +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native(Box::new(MyApp::default()), options); +} diff --git a/eframe/src/lib.rs b/eframe/src/lib.rs index dd37d890..1f330f76 100644 --- a/eframe/src/lib.rs +++ b/eframe/src/lib.rs @@ -61,6 +61,6 @@ pub fn start_web(canvas_id: &str, app: Box) -> Result<(), wasm_bin /// Call from `fn main` like this: `eframe::run_native(Box::new(MyEguiApp::default()))` #[cfg(not(target_arch = "wasm32"))] -pub fn run_native(app: Box, native_options: epi::NativeOptions) { +pub fn run_native(app: Box, native_options: epi::NativeOptions) -> ! { egui_glium::run(app, &native_options) } diff --git a/egui_glium/CHANGELOG.md b/egui_glium/CHANGELOG.md index 1cd5df85..13fd72a7 100644 --- a/egui_glium/CHANGELOG.md +++ b/egui_glium/CHANGELOG.md @@ -1,5 +1,4 @@ # Changelog for egui_glium - All notable changes to the `egui_glium` integration will be noted in this file. @@ -10,6 +9,7 @@ All notable changes to the `egui_glium` integration will be noted in this file. * Increase scroll speed. * Restore window position on startup without flickering. * A lot of the code has been moved to the new library [`egui-winit`](https://github.com/emilk/egui/tree/master/egui-winit). +* Fix reactive mode on windows. ## 0.14.0 - 2021-08-24 diff --git a/egui_glium/src/backend.rs b/egui_glium/src/backend.rs index 8befea20..e32767f0 100644 --- a/egui_glium/src/backend.rs +++ b/egui_glium/src/backend.rs @@ -160,12 +160,12 @@ fn load_icon(icon_data: epi::IconData) -> Option { // ---------------------------------------------------------------------------- /// Run an egui app -pub fn run(mut app: Box, native_options: &epi::NativeOptions) { +pub fn run(mut app: Box, native_options: &epi::NativeOptions) -> ! { #[allow(unused_mut)] let mut storage = create_storage(app.name()); let window_settings = deserialize_window_settings(&storage); - let mut event_loop = glutin::event_loop::EventLoop::with_user_event(); + let event_loop = glutin::event_loop::EventLoop::with_user_event(); let icon = native_options.icon_data.clone().and_then(load_icon); let display = create_display(&*app, native_options, &window_settings, icon, &event_loop); @@ -191,6 +191,8 @@ pub fn run(mut app: Box, native_options: &epi::NativeOptions) { let mut previous_frame_time = None; + let mut is_focused = true; + #[cfg(feature = "persistence")] let mut last_auto_save = Instant::now(); @@ -220,68 +222,8 @@ pub fn run(mut app: Box, native_options: &epi::NativeOptions) { // eprintln!("Warmed up in {} ms", warm_up_start.elapsed().as_millis()) } - let mut is_focused = true; - let mut running = true; - let mut repaint_asap = true; - - while running { - use glium::glutin::platform::run_return::EventLoopExtRunReturn as _; - event_loop.run_return(|event, _, control_flow| { - use glium::glutin::event_loop::ControlFlow; - - *control_flow = ControlFlow::Wait; - - match event { - // Platform-dependent event handlers to workaround a winit bug - // See: https://github.com/rust-windowing/winit/issues/987 - // See: https://github.com/rust-windowing/winit/issues/1619 - glutin::event::Event::RedrawEventsCleared if cfg!(windows) => { - *control_flow = ControlFlow::Exit; // Time to redraw - } - glutin::event::Event::RedrawRequested(_) if !cfg!(windows) => { - *control_flow = ControlFlow::Exit; // Time to redraw - } - glutin::event::Event::MainEventsCleared => { - if repaint_asap { - *control_flow = ControlFlow::Exit; // Time to redraw - } else { - // Winit uses up all the CPU of one core when returning ControlFlow::Wait. - // Sleeping here helps, but still uses 1-3% of CPU :( - if is_focused || !egui.egui_input().hovered_files.is_empty() { - std::thread::sleep(std::time::Duration::from_millis(10)); - } else { - std::thread::sleep(std::time::Duration::from_millis(50)); - } - } - } - glutin::event::Event::WindowEvent { event, .. } => { - if egui.is_quit_event(&event) { - *control_flow = ControlFlow::Exit; - running = false; - } - - if let glutin::event::WindowEvent::Focused(new_focused) = event { - is_focused = new_focused; - } - - egui.on_event(&event); - - // TODO: ask egui if the events warrants a repaint instead of repainting on each event. - display.gl_window().window().request_redraw(); - repaint_asap = true; - } - glutin::event::Event::UserEvent(RequestRepaintEvent) => { - display.gl_window().window().request_redraw(); - *control_flow = ControlFlow::Exit; // Time to redraw - } - - _ => (), - } - }); - - repaint_asap = false; - - if running { + event_loop.run(move |event, _, control_flow| { + let mut redraw = || { if !is_focused { // On Mac, a minimized Window uses up all CPU: https://github.com/emilk/egui/issues/325 // We can't know if we are minimized: https://github.com/rust-windowing/winit/issues/208 @@ -349,11 +291,13 @@ pub fn run(mut app: Box, native_options: &epi::NativeOptions) { let _ = display.gl_window().window().drag_window(); } - if quit { - running = false; + *control_flow = if quit { + glutin::event_loop::ControlFlow::Exit } else if needs_repaint { display.gl_window().window().request_redraw(); - repaint_asap = true; + glutin::event_loop::ControlFlow::Poll + } else { + glutin::event_loop::ControlFlow::Wait }; } @@ -376,24 +320,52 @@ pub fn run(mut app: Box, native_options: &epi::NativeOptions) { last_auto_save = now; } } - } - } + }; - app.on_exit(); + match event { + // Platform-dependent event handlers to workaround a winit bug + // See: https://github.com/rust-windowing/winit/issues/987 + // See: https://github.com/rust-windowing/winit/issues/1619 + glutin::event::Event::RedrawEventsCleared if cfg!(windows) => redraw(), + glutin::event::Event::RedrawRequested(_) if !cfg!(windows) => redraw(), - #[cfg(feature = "persistence")] - if let Some(storage) = &mut storage { - if app.persist_native_window() { - epi::set_value( - storage.as_mut(), - WINDOW_KEY, - &WindowSettings::from_display(&display), - ); + glutin::event::Event::WindowEvent { event, .. } => { + if egui.is_quit_event(&event) { + *control_flow = glium::glutin::event_loop::ControlFlow::Exit; + } + + if let glutin::event::WindowEvent::Focused(new_focused) = event { + is_focused = new_focused; + } + + egui.on_event(&event); + + display.gl_window().window().request_redraw(); // TODO: ask egui if the events warrants a repaint instead + } + glutin::event::Event::LoopDestroyed => { + app.on_exit(); + #[cfg(feature = "persistence")] + if let Some(storage) = &mut storage { + if app.persist_native_window() { + epi::set_value( + storage.as_mut(), + WINDOW_KEY, + &WindowSettings::from_display(&display), + ); + } + if app.persist_egui_memory() { + epi::set_value(storage.as_mut(), EGUI_MEMORY_KEY, &*egui.ctx().memory()); + } + app.save(storage.as_mut()); + storage.flush(); + } + } + + glutin::event::Event::UserEvent(RequestRepaintEvent) => { + display.gl_window().window().request_redraw(); + } + + _ => (), } - if app.persist_egui_memory() { - epi::set_value(storage.as_mut(), EGUI_MEMORY_KEY, &*egui.ctx().memory()); - } - app.save(storage.as_mut()); - storage.flush(); - } + }); }