diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index fc97e1b81..407c0abfa 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -69,7 +69,7 @@ trait WinitApp { /// The current frame number, as reported by egui. fn frame_nr(&self) -> u64; - fn is_focused(&self) -> bool; + fn is_focused(&self, window_id: winit::window::WindowId) -> bool; fn integration(&self) -> Option<&EpiIntegration>; @@ -243,7 +243,7 @@ fn run_and_return( for (window_id, repaint_time) in windows_next_repaint_times.clone().iter() { if *repaint_time <= Instant::now() { if let Some(window) = winit_app.window(*window_id) { - log::trace!("request_redraw"); + log::trace!("request_redraw {window_id:?}"); window.request_redraw(); windows_next_repaint_times.remove(window_id); } @@ -748,7 +748,7 @@ mod glow_integration { // re-initializing the `GlowWinitRunning` state on Android if the application // suspends and resumes. app_creator: Option, - is_focused: bool, + is_focused: Option, } impl GlowWinitApp { @@ -764,7 +764,7 @@ mod glow_integration { native_options, running: None, app_creator: Some(app_creator), - is_focused: true, + is_focused: Some(0), } } @@ -842,6 +842,12 @@ mod glow_integration { let theme = system_theme.unwrap_or(self.native_options.default_theme); integration.egui_ctx.set_visuals(theme.egui_visuals()); + // !!! WARNING This is needed to be improved !!! + // I don't really know not to detect if is on desktop or web/mobile + // This allows to have multiples windows + + integration.egui_ctx.set_desktop(true); + gl_window.window(0).set_ime_allowed(true); if self.native_options.mouse_passthrough { gl_window.window(0).set_cursor_hittest(false).unwrap(); @@ -902,8 +908,15 @@ mod glow_integration { .map_or(0, |r| r.integration.egui_ctx.frame_nr()) } - fn is_focused(&self) -> bool { - self.is_focused + fn is_focused(&self, window_id: winit::window::WindowId) -> bool { + if let Some(is_focused) = self.is_focused { + if let Some(running) = &self.running { + if let Some(window_id) = running.gl_window.window_maps.get(&window_id) { + return is_focused == *window_id; + } + } + } + false } fn integration(&self) -> Option<&EpiIntegration> { @@ -1215,7 +1228,9 @@ mod glow_integration { match &event { winit::event::WindowEvent::Focused(new_focused) => { - self.is_focused = *new_focused; + self.is_focused = new_focused + .then(|| running.gl_window.window_maps.get(window_id).cloned()) + .flatten(); } winit::event::WindowEvent::Resized(physical_size) => { repaint_asap = true; @@ -1503,7 +1518,7 @@ mod wgpu_integration { .map_or(0, |r| r.integration.egui_ctx.frame_nr()) } - fn is_focused(&self) -> bool { + fn is_focused(&self, _: winit::window::WindowId) -> bool { self.is_focused } diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 21dea8fe1..c3d15c1c1 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -444,13 +444,7 @@ impl<'open> Window<'open> { window_builder, } = self; - let window_id = if !embedded { - ctx.create_window(window_builder) - } else { - 0 - }; - - if embedded || ctx.current_window_id() == window_id { + let draw = move || { let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style())); let is_explicitly_closed = matches!(open, Some(false)); @@ -608,8 +602,13 @@ impl<'open> Window<'open> { response: full_response, }; Some(inner_response) + }; + + if !embedded { + ctx.create_window(window_builder, |window_id| draw()) + .flatten() } else { - None + draw() } } } diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index de2281f89..1d91591ec 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -162,7 +162,10 @@ struct ContextImpl { windows: HashMap, window_counter: u64, - current_window_id: u64, + current_rendering_window: u64, + windows_stack: Vec, + current_window: u64, + is_desktop: bool, /// Written to during the frame. layer_rects_this_frame: ahash::HashMap>, @@ -965,7 +968,7 @@ impl Context { /// (this will work on `eframe`). pub fn request_repaint(&self) { // request two frames of repaint, just to cover some corner cases (frame delays): - self.write(|ctx| ctx.repaint.request_repaint(ctx.current_window_id)); + self.write(|ctx| ctx.repaint.request_repaint(ctx.current_window)); } /// Request repaint after at most the specified duration elapses. @@ -1468,7 +1471,7 @@ impl Context { } pub(crate) fn rect_contains_pointer(&self, layer_id: LayerId, rect: Rect) -> bool { - rect.is_positive() && { + rect.is_positive() && self.current_window() == self.current_rendering_window() && { let pointer_pos = self.input(|i| i.pointer.interact_pos()); if let Some(pointer_pos) = pointer_pos { rect.contains(pointer_pos) && self.layer_id_at(pointer_pos) == Some(layer_id) @@ -1893,25 +1896,56 @@ use containers::window::WindowBuilder; /// # Windows impl Context { pub fn set_current_window_id(&self, window_id: u64) { - self.write(|ctx| ctx.current_window_id = window_id); + self.write(|ctx| ctx.current_rendering_window = window_id); } - pub fn current_window_id(&self) -> u64 { - self.read(|ctx| ctx.current_window_id) + pub fn current_rendering_window(&self) -> u64 { + self.read(|ctx| ctx.current_rendering_window) } - pub fn create_window(&self, window_builder: WindowBuilder) -> u64 { - self.write(|ctx| { - if let Some(window) = ctx.windows.get_mut(&window_builder.title) { - window.2 = true; - window.1 + pub fn current_window(&self) -> u64 { + self.read(|ctx| ctx.current_window) + } + + pub fn is_desktop(&self) -> bool { + self.read(|ctx| ctx.is_desktop) + } + + pub fn set_desktop(&self, value: bool) { + self.write(|ctx| ctx.is_desktop = value) + } + + pub fn create_window( + &self, + window_builder: WindowBuilder, + func: impl FnOnce(u64) -> T, + ) -> Option { + let id = self.write(|ctx| { + if ctx.is_desktop { + if let Some(window) = ctx.windows.get_mut(&window_builder.title) { + window.2 = true; + window.1 + } else { + let id = ctx.window_counter + 1; + ctx.window_counter = id; + ctx.windows + .insert(window_builder.title.clone(), (window_builder, id, true)); + id + } } else { - let id = ctx.window_counter + 1; - ctx.window_counter = id; - ctx.windows - .insert(window_builder.title.clone(), (window_builder, id, true)); - id + 0 } - }) + }); + let should_render = self.write(|ctx| { + ctx.windows_stack.push(id); + ctx.current_window = id; + ctx.current_window == ctx.current_rendering_window + }); + let out = if should_render { Some(func(id)) } else { None }; + self.write(|ctx| { + ctx.windows_stack.pop(); + ctx.current_window = ctx.windows_stack.pop().unwrap_or(0); + }); + out } } diff --git a/crates/egui/src/painter.rs b/crates/egui/src/painter.rs index 214bbe175..c3f4ab082 100644 --- a/crates/egui/src/painter.rs +++ b/crates/egui/src/painter.rs @@ -168,6 +168,10 @@ impl Painter { /// Can be used for free painting. /// NOTE: all coordinates are screen coordinates! pub fn add(&self, shape: impl Into) -> ShapeIdx { + if self.ctx.current_window() != self.ctx.current_rendering_window() { + return self + .paint_list(|l| l.add(Rect::from_min_size(Pos2::ZERO, Vec2::ZERO), Shape::Noop)); + } if self.fade_to_color == Some(Color32::TRANSPARENT) { self.paint_list(|l| l.add(self.clip_rect, Shape::Noop)) } else { @@ -181,7 +185,9 @@ impl Painter { /// /// Calling this once is generally faster than calling [`Self::add`] multiple times. pub fn extend>(&self, shapes: I) { - if self.fade_to_color == Some(Color32::TRANSPARENT) { + if self.fade_to_color == Some(Color32::TRANSPARENT) + || self.ctx.current_window() != self.ctx.current_rendering_window() + { return; } if self.fade_to_color.is_some() { @@ -197,7 +203,9 @@ impl Painter { /// Modify an existing [`Shape`]. pub fn set(&self, idx: ShapeIdx, shape: impl Into) { - if self.fade_to_color == Some(Color32::TRANSPARENT) { + if self.fade_to_color == Some(Color32::TRANSPARENT) + || self.ctx.current_window() != self.ctx.current_rendering_window() + { return; } let mut shape = shape.into(); @@ -390,6 +398,9 @@ impl Painter { font_id: FontId, text_color: Color32, ) -> Rect { + if self.ctx.current_window() != self.ctx.current_rendering_window() { + return Rect::from_min_size(Pos2::ZERO, Vec2::ZERO); + } let galley = self.layout_no_wrap(text.to_string(), font_id, text_color); let rect = anchor.anchor_rect(Rect::from_min_size(pos, galley.size())); self.galley(rect.min, galley); diff --git a/crates/egui_demo_app/src/backend_panel.rs b/crates/egui_demo_app/src/backend_panel.rs index c1e1fc4ad..d1df6a1f0 100644 --- a/crates/egui_demo_app/src/backend_panel.rs +++ b/crates/egui_demo_app/src/backend_panel.rs @@ -283,7 +283,7 @@ impl BackendPanel { log::info!("Request a repaint in 3s..."); ctx.request_repaint_after( std::time::Duration::from_secs(3), - ctx.current_window_id(), + ctx.current_rendering_window(), ); }); } diff --git a/examples/hello_world_simple/src/main.rs b/examples/hello_world_simple/src/main.rs index 1ee6ff032..4d1a1fd3c 100644 --- a/examples/hello_world_simple/src/main.rs +++ b/examples/hello_world_simple/src/main.rs @@ -19,6 +19,11 @@ fn main() -> Result<(), eframe::Error> { eframe::run_simple_native("My egui App", options, move |ctx, _frame| { egui::CentralPanel::default().show(ctx, |ui| { + ui.label(format!( + "Current window: {}, Current rendering window: {}", + ctx.current_window(), + ctx.current_rendering_window() + )); ui.heading("My egui Application"); ui.horizontal(|ui| { let name_label = ui.label("Your name: "); diff --git a/examples/user_attention/src/main.rs b/examples/user_attention/src/main.rs index 736015623..a7e3c16e2 100644 --- a/examples/user_attention/src/main.rs +++ b/examples/user_attention/src/main.rs @@ -128,6 +128,6 @@ impl eframe::App for Application { }); }); - ctx.request_repaint_after(Self::repaint_max_timeout(), ctx.current_window_id()); + ctx.request_repaint_after(Self::repaint_max_timeout(), ctx.current_rendering_window()); } }