From 8f475ef8d828ad1b90927320557004918661def9 Mon Sep 17 00:00:00 2001 From: Konkitoman Date: Tue, 18 Jul 2023 16:50:41 +0300 Subject: [PATCH] Is creating a window --- crates/eframe/src/native/run.rs | 180 +++++++++++++++--------- crates/egui/src/containers/window.rs | 31 +++- crates/egui/src/context.rs | 6 +- examples/hello_world_simple/src/main.rs | 3 + 4 files changed, 149 insertions(+), 71 deletions(-) diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 720448513..4c9589c72 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -401,6 +401,7 @@ mod glow_integration { use std::sync::Arc; use egui::{epaint::ahash::HashMap, window::WindowBuilder, NumExt as _}; + use glow::HasContext; use glutin::{ display::GetGlDisplay, prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentGlContext}, @@ -601,63 +602,76 @@ mod glow_integration { /// we presently assume that we will #[allow(unsafe_code)] fn on_resume(&mut self, event_loop: &EventLoopWindowTarget) -> Result<()> { - if self.windows[0].gl_surface.is_some() { - log::warn!("on_resume called even thought we already have a surface. early return"); - return Ok(()); + for win in self.windows.iter_mut() { + if win.gl_surface.is_some() { + continue; + } + log::debug!("running on_resume fn."); + // make sure we have a window or create one. + let window = win.window.take().unwrap_or_else(|| { + log::debug!("window doesn't exist yet. creating one now with finalize_window"); + glutin_winit::finalize_window( + event_loop, + create_winit_window_builder(&win.builder), + &self.gl_config, + ) + .expect("failed to finalize glutin window") + }); + // surface attributes + let (width, height): (u32, u32) = window.inner_size().into(); + let width = std::num::NonZeroU32::new(width.at_least(1)).unwrap(); + let height = std::num::NonZeroU32::new(height.at_least(1)).unwrap(); + let surface_attributes = glutin::surface::SurfaceAttributesBuilder::< + glutin::surface::WindowSurface, + >::new() + .build(window.raw_window_handle(), width, height); + log::debug!( + "creating surface with attributes: {:?}", + &surface_attributes + ); + // create surface + let gl_surface = unsafe { + self.gl_config + .display() + .create_window_surface(&self.gl_config, &surface_attributes)? + }; + log::debug!("surface created successfully: {gl_surface:?}.making context current"); + // make surface and context current. + let not_current_gl_context = + if let Some(not_current_context) = self.not_current_gl_context.take() { + not_current_context + } else { + self.current_gl_context + .take() + .unwrap() + .make_not_current() + .unwrap() + }; + let current_gl_context = not_current_gl_context.make_current(&gl_surface)?; + // try setting swap interval. but its not absolutely necessary, so don't panic on failure. + log::debug!("made context current. setting swap interval for surface"); + if let Err(e) = + gl_surface.set_swap_interval(¤t_gl_context, self.swap_interval) + { + log::error!("failed to set swap interval due to error: {e:?}"); + } + // we will reach this point only once in most platforms except android. + // create window/surface/make context current once and just use them forever. + win.gl_surface = Some(gl_surface); + self.current_gl_context = Some(current_gl_context); + self.window_maps.insert(window.id(), win.window_id); + win.window = Some(window); } - log::debug!("running on_resume fn."); - // make sure we have a window or create one. - let window = self.windows[0].window.take().unwrap_or_else(|| { - log::debug!("window doesn't exist yet. creating one now with finalize_window"); - glutin_winit::finalize_window( - event_loop, - create_winit_window_builder(&self.windows[0].builder), - &self.gl_config, - ) - .expect("failed to finalize glutin window") - }); - // surface attributes - let (width, height): (u32, u32) = window.inner_size().into(); - let width = std::num::NonZeroU32::new(width.at_least(1)).unwrap(); - let height = std::num::NonZeroU32::new(height.at_least(1)).unwrap(); - let surface_attributes = - glutin::surface::SurfaceAttributesBuilder::::new() - .build(window.raw_window_handle(), width, height); - log::debug!( - "creating surface with attributes: {:?}", - &surface_attributes - ); - // create surface - let gl_surface = unsafe { - self.gl_config - .display() - .create_window_surface(&self.gl_config, &surface_attributes)? - }; - log::debug!("surface created successfully: {gl_surface:?}.making context current"); - // make surface and context current. - let not_current_gl_context = self - .not_current_gl_context - .take() - .expect("failed to get not current context after resume event. impossible!"); - let current_gl_context = not_current_gl_context.make_current(&gl_surface)?; - // try setting swap interval. but its not absolutely necessary, so don't panic on failure. - log::debug!("made context current. setting swap interval for surface"); - if let Err(e) = gl_surface.set_swap_interval(¤t_gl_context, self.swap_interval) { - log::error!("failed to set swap interval due to error: {e:?}"); - } - // we will reach this point only once in most platforms except android. - // create window/surface/make context current once and just use them forever. - self.windows[0].gl_surface = Some(gl_surface); - self.current_gl_context = Some(current_gl_context); - self.windows[0].window = Some(window); Ok(()) } /// only applies for android. but we basically drop surface + window and make context not current fn on_suspend(&mut self) -> Result<()> { log::debug!("received suspend event. dropping window and surface"); - self.windows[0].gl_surface.take(); - self.windows[0].window.take(); + for window in self.windows.iter_mut() { + window.gl_surface.take(); + window.window.take(); + } if let Some(current) = self.current_gl_context.take() { log::debug!("context is current, so making it non-current"); self.not_current_gl_context = Some(current.make_not_current()?); @@ -674,20 +688,31 @@ mod glow_integration { .expect("winit window doesn't exist") } - fn resize(&self, physical_size: winit::dpi::PhysicalSize) { + fn resize(&mut self, window_id: u64, physical_size: winit::dpi::PhysicalSize) { let width = std::num::NonZeroU32::new(physical_size.width.at_least(1)).unwrap(); let height = std::num::NonZeroU32::new(physical_size.height.at_least(1)).unwrap(); - self.windows[0] - .gl_surface - .as_ref() - .expect("failed to get surface to resize") - .resize( - self.current_gl_context - .as_ref() - .expect("failed to get current context to resize surface"), - width, - height, - ); + for window in self.windows.iter_mut() { + if window.window_id == window_id { + if let Some(gl_surface) = &window.gl_surface { + self.current_gl_context = Some( + self.current_gl_context + .take() + .unwrap() + .make_not_current() + .unwrap() + .make_current(&gl_surface) + .unwrap(), + ); + gl_surface.resize( + self.current_gl_context + .as_ref() + .expect("failed to get current context to resize surface"), + width, + height, + ); + } + } + } } fn swap_buffers(&self) -> glutin::error::Result<()> { @@ -958,7 +983,20 @@ mod glow_integration { let control_flow; { - let window = gl_window.window(window_index); + // let window = gl_window.window(window_index); + let win: Option<&Window> = gl_window.windows.get(window_index); + let win = win.unwrap(); + let window = win.window.as_ref().unwrap(); + gl_window.current_gl_context = Some( + gl_window + .current_gl_context + .take() + .unwrap() + .make_not_current() + .unwrap() + .make_current(win.gl_surface.as_ref().unwrap()) + .unwrap(), + ); let screen_size_in_pixels: [u32; 2] = window.inner_size().into(); @@ -1104,6 +1142,7 @@ mod glow_integration { window: None, window_id: id, }); + wins.push(id); } gl_window.windows.retain(|w| wins.contains(&w.window_id)); @@ -1170,6 +1209,13 @@ mod glow_integration { EventResult::Wait } + winit::event::Event::MainEventsCleared => { + if let Some(running) = self.running.as_mut() { + running.gl_window.on_resume(event_loop); + } + EventResult::Wait + } + winit::event::Event::WindowEvent { event, window_id } => { if let Some(running) = &mut self.running { // On Windows, if a window is resized by the user, it should repaint synchronously, inside the @@ -1198,7 +1244,9 @@ mod glow_integration { // See: https://github.com/rust-windowing/winit/issues/208 // This solves an issue where the app would panic when minimizing on Windows. if physical_size.width > 0 && physical_size.height > 0 { - running.gl_window.resize(*physical_size); + if let Some(id) = running.gl_window.window_maps.get(window_id) { + running.gl_window.resize(*id, *physical_size); + } } } winit::event::WindowEvent::ScaleFactorChanged { @@ -1206,7 +1254,9 @@ mod glow_integration { .. } => { repaint_asap = true; - running.gl_window.resize(**new_inner_size); + if let Some(id) = running.gl_window.window_maps.get(window_id) { + running.gl_window.resize(*id, **new_inner_size); + } } winit::event::WindowEvent::CloseRequested if running.integration.should_close() => diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 09e47b2b4..fa98d1f63 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -6,7 +6,7 @@ use epaint::*; use super::*; -#[derive(Hash, PartialEq, Clone, Default)] +#[derive(Hash, PartialEq, Clone)] pub struct WindowBuilder { pub title: String, pub name: Option, @@ -28,6 +28,31 @@ pub struct WindowBuilder { pub drag_and_drop: bool, } +impl Default for WindowBuilder { + fn default() -> Self { + Self { + title: "Dummy EGUI Window".into(), + name: None, + position: None, + inner_size: Some((600, 500)), + fullscreen: false, + maximized: false, + resizable: true, + transparent: false, + decorations: true, + icon: None, + active: true, + visible: true, + title_hidden: false, + titlebar_transparent: false, + fullsize_content_view: false, + min_inner_size: None, + max_inner_size: None, + drag_and_drop: true, + } + } +} + impl WindowBuilder { pub fn with_title(mut self, title: impl Into) -> Self { self.title = title.into(); @@ -396,8 +421,8 @@ impl<'open> Window<'open> { ctx: &Context, add_contents: Box R + 'c>, ) -> Option>> { - let window_id = - ctx.data_mut(|data| *data.get_temp_mut_or(self.area.id.with("window_id"), 0)); + let window_id = ctx.create_window(WindowBuilder::default().with_title(self.title.text())); + println!("Window id: {}", window_id); let Window { title, open, diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index cbd9d1a9d..739b672dd 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -1268,10 +1268,10 @@ impl Context { let repaint_after = self.write(|ctx| ctx.repaint.end_frame()); let shapes = self.drain_paint_lists(); - let windows = self.write(|ctx| { + let windows = self.read(|ctx| { ctx.windows - .drain() - .map(|(_, (builder, id, _))| (id, builder)) + .iter() + .map(|(_, (builder, id, _))| (*id, builder.clone())) .collect() }); diff --git a/examples/hello_world_simple/src/main.rs b/examples/hello_world_simple/src/main.rs index bc815738b..b2eeb94ed 100644 --- a/examples/hello_world_simple/src/main.rs +++ b/examples/hello_world_simple/src/main.rs @@ -27,6 +27,9 @@ fn main() -> Result<(), eframe::Error> { age += 1; } ui.label(format!("Hello '{name}', age {age}")); + egui::CollapsingHeader::new("W").show(ui, |ui| { + egui::Window::new("Win").show(ctx, |ui| ui.label("Inside a window!")); + }); }); }) }