mirror of
https://github.com/emilk/egui.git
synced 2026-08-31 22:00:03 -04:00
Update to winit 0.29 (#3649)
* Closes https://github.com/emilk/egui/issues/3542 * Closes https://github.com/emilk/egui/issues/2977 * Closes https://github.com/emilk/egui/issues/3303 --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
@@ -1,8 +1,17 @@
|
||||
//! Note that this file contains code very similar to [`wgpu_integration`].
|
||||
//! When making changes to one you often also want to apply it to the other.
|
||||
//!
|
||||
//! This is also very complex code, and not very pretty.
|
||||
//! There is a bunch of improvements we could do,
|
||||
//! like removing a bunch of `unwraps`.
|
||||
|
||||
use std::{cell::RefCell, rc::Rc, sync::Arc, time::Instant};
|
||||
|
||||
use glutin::{
|
||||
config::GlConfig,
|
||||
context::NotCurrentGlContext,
|
||||
display::GetGlDisplay,
|
||||
prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentGlContext},
|
||||
prelude::{GlDisplay, PossiblyCurrentGlContext},
|
||||
surface::GlSurface,
|
||||
};
|
||||
use raw_window_handle::{HasRawDisplayHandle as _, HasRawWindowHandle as _};
|
||||
@@ -112,6 +121,8 @@ struct Viewport {
|
||||
/// None for immediate viewports.
|
||||
viewport_ui_cb: Option<Arc<DeferredViewportUiCallback>>,
|
||||
|
||||
// These three live and die together.
|
||||
// TODO(emilk): clump them together into one struct!
|
||||
gl_surface: Option<glutin::surface::Surface<glutin::surface::WindowSurface>>,
|
||||
window: Option<Rc<Window>>,
|
||||
egui_winit: Option<egui_winit::State>,
|
||||
@@ -160,12 +171,12 @@ impl GlowWinitApp {
|
||||
};
|
||||
|
||||
// Creates the window - must come before we create our glow context
|
||||
glutin_window_context.on_resume(event_loop)?;
|
||||
glutin_window_context.initialize_window(ViewportId::ROOT, event_loop)?;
|
||||
|
||||
if let Some(viewport) = glutin_window_context.viewports.get(&ViewportId::ROOT) {
|
||||
if let Some(window) = &viewport.window {
|
||||
epi_integration::apply_window_settings(window, window_settings);
|
||||
}
|
||||
{
|
||||
let viewport = &glutin_window_context.viewports[&ViewportId::ROOT];
|
||||
let window = viewport.window.as_ref().unwrap(); // Can't fail - we just called `initialize_all_viewports`
|
||||
epi_integration::apply_window_settings(window, window_settings);
|
||||
}
|
||||
|
||||
let gl = unsafe {
|
||||
@@ -390,9 +401,13 @@ impl WinitApp for GlowWinitApp {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_ui_and_paint(&mut self, window_id: WindowId) -> EventResult {
|
||||
fn run_ui_and_paint(
|
||||
&mut self,
|
||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||
window_id: WindowId,
|
||||
) -> EventResult {
|
||||
if let Some(running) = &mut self.running {
|
||||
running.run_ui_and_paint(window_id)
|
||||
running.run_ui_and_paint(event_loop, window_id)
|
||||
} else {
|
||||
EventResult::Wait
|
||||
}
|
||||
@@ -401,29 +416,27 @@ impl WinitApp for GlowWinitApp {
|
||||
fn on_event(
|
||||
&mut self,
|
||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||
event: &winit::event::Event<'_, UserEvent>,
|
||||
event: &winit::event::Event<UserEvent>,
|
||||
) -> Result<EventResult> {
|
||||
crate::profile_function!(winit_integration::short_event_description(event));
|
||||
|
||||
Ok(match event {
|
||||
winit::event::Event::Resumed => {
|
||||
log::debug!("Event::Resumed");
|
||||
|
||||
let running = if let Some(running) = &mut self.running {
|
||||
// not the first resume event. create whatever you need.
|
||||
running.glutin.borrow_mut().on_resume(event_loop)?;
|
||||
// Not the first resume event. Create all outstanding windows.
|
||||
running
|
||||
.glutin
|
||||
.borrow_mut()
|
||||
.initialize_all_windows(event_loop);
|
||||
running
|
||||
} else {
|
||||
// first resume event.
|
||||
// we can actually move this outside of event loop.
|
||||
// and just run the on_resume fn of gl_window
|
||||
// First resume event. Created our root window etc.
|
||||
self.init_run_state(event_loop)?
|
||||
};
|
||||
let window_id = running
|
||||
.glutin
|
||||
.borrow()
|
||||
.window_from_viewport
|
||||
.get(&ViewportId::ROOT)
|
||||
.copied();
|
||||
EventResult::RepaintNow(window_id.unwrap())
|
||||
let window_id = running.glutin.borrow().window_from_viewport[&ViewportId::ROOT];
|
||||
EventResult::RepaintNow(window_id)
|
||||
}
|
||||
|
||||
winit::event::Event::Suspended => {
|
||||
@@ -433,15 +446,6 @@ impl WinitApp for GlowWinitApp {
|
||||
EventResult::Wait
|
||||
}
|
||||
|
||||
winit::event::Event::MainEventsCleared => {
|
||||
if let Some(running) = &self.running {
|
||||
if let Err(err) = running.glutin.borrow_mut().on_resume(event_loop) {
|
||||
log::warn!("on_resume failed {err}");
|
||||
}
|
||||
}
|
||||
EventResult::Wait
|
||||
}
|
||||
|
||||
winit::event::Event::WindowEvent { event, window_id } => {
|
||||
if let Some(running) = &mut self.running {
|
||||
running.on_window_event(*window_id, event)
|
||||
@@ -477,7 +481,11 @@ impl WinitApp for GlowWinitApp {
|
||||
}
|
||||
|
||||
impl GlowWinitRunning {
|
||||
fn run_ui_and_paint(&mut self, window_id: WindowId) -> EventResult {
|
||||
fn run_ui_and_paint(
|
||||
&mut self,
|
||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||
window_id: WindowId,
|
||||
) -> EventResult {
|
||||
crate::profile_function!();
|
||||
|
||||
let Some(viewport_id) = self
|
||||
@@ -666,7 +674,7 @@ impl GlowWinitRunning {
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
}
|
||||
|
||||
glutin.handle_viewport_output(&integration.egui_ctx, viewport_output);
|
||||
glutin.handle_viewport_output(event_loop, &integration.egui_ctx, viewport_output);
|
||||
|
||||
if integration.should_close() {
|
||||
EventResult::Exit
|
||||
@@ -678,7 +686,7 @@ impl GlowWinitRunning {
|
||||
fn on_window_event(
|
||||
&mut self,
|
||||
window_id: WindowId,
|
||||
event: &winit::event::WindowEvent<'_>,
|
||||
event: &winit::event::WindowEvent,
|
||||
) -> EventResult {
|
||||
crate::profile_function!(egui_winit::short_window_event_description(event));
|
||||
|
||||
@@ -717,13 +725,6 @@ impl GlowWinitRunning {
|
||||
}
|
||||
}
|
||||
|
||||
winit::event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
||||
if let Some(viewport_id) = viewport_id {
|
||||
repaint_asap = true;
|
||||
glutin.resize(viewport_id, **new_inner_size);
|
||||
}
|
||||
}
|
||||
|
||||
winit::event::WindowEvent::CloseRequested => {
|
||||
if viewport_id == Some(ViewportId::ROOT) && self.integration.should_close() {
|
||||
log::debug!(
|
||||
@@ -768,7 +769,11 @@ impl GlowWinitRunning {
|
||||
{
|
||||
event_response = self.integration.on_window_event(window, egui_winit, event);
|
||||
}
|
||||
} else {
|
||||
log::trace!("Ignoring event: no viewport for {viewport_id:?}");
|
||||
}
|
||||
} else {
|
||||
log::trace!("Ignoring event: no viewport_id");
|
||||
}
|
||||
|
||||
if event_response.repaint {
|
||||
@@ -855,7 +860,7 @@ impl GlutinWindowContext {
|
||||
// Create GL display. This may probably create a window too on most platforms. Definitely on `MS windows`. Never on Android.
|
||||
let display_builder = glutin_winit::DisplayBuilder::new()
|
||||
// we might want to expose this option to users in the future. maybe using an env var or using native_options.
|
||||
.with_preference(glutin_winit::ApiPrefence::FallbackEgl) // https://github.com/emilk/egui/issues/2520#issuecomment-1367841150
|
||||
.with_preference(glutin_winit::ApiPreference::FallbackEgl) // https://github.com/emilk/egui/issues/2520#issuecomment-1367841150
|
||||
.with_window_builder(Some(egui_winit::create_winit_window_builder(
|
||||
egui_ctx,
|
||||
event_loop,
|
||||
@@ -968,37 +973,29 @@ impl GlutinWindowContext {
|
||||
focused_viewport: Some(ViewportId::ROOT),
|
||||
};
|
||||
|
||||
slf.on_resume(event_loop)?;
|
||||
slf.initialize_window(ViewportId::ROOT, event_loop)?;
|
||||
|
||||
Ok(slf)
|
||||
}
|
||||
|
||||
/// This will be run after `new`. on android, it might be called multiple times over the course of the app's lifetime.
|
||||
/// roughly,
|
||||
/// 1. check if window already exists. otherwise, create one now.
|
||||
/// 2. create attributes for surface creation.
|
||||
/// 3. create surface.
|
||||
/// 4. make surface and context current.
|
||||
/// Create a surface, window, and winit integration for all viewports lacking any of that.
|
||||
///
|
||||
/// we presently assume that we will
|
||||
fn on_resume(&mut self, event_loop: &EventLoopWindowTarget<UserEvent>) -> Result<()> {
|
||||
/// Errors will be logged.
|
||||
fn initialize_all_windows(&mut self, event_loop: &EventLoopWindowTarget<UserEvent>) {
|
||||
crate::profile_function!();
|
||||
|
||||
let viewports: Vec<ViewportId> = self
|
||||
.viewports
|
||||
.iter()
|
||||
.filter(|(_, viewport)| viewport.gl_surface.is_none())
|
||||
.map(|(id, _)| *id)
|
||||
.collect();
|
||||
let viewports: Vec<ViewportId> = self.viewports.keys().copied().collect();
|
||||
|
||||
for viewport_id in viewports {
|
||||
self.init_viewport(viewport_id, event_loop)?;
|
||||
if let Err(err) = self.initialize_window(viewport_id, event_loop) {
|
||||
log::error!("Failed to initialize a window for viewport {viewport_id:?}: {err}");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a surface, window, and winit integration for the viewport, if missing.
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn init_viewport(
|
||||
pub(crate) fn initialize_window(
|
||||
&mut self,
|
||||
viewport_id: ViewportId,
|
||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||
@@ -1013,12 +1010,16 @@ impl GlutinWindowContext {
|
||||
let window = if let Some(window) = &mut viewport.window {
|
||||
window
|
||||
} else {
|
||||
log::trace!("Window doesn't exist yet. Creating one now with finalize_window");
|
||||
log::debug!("Creating a window for viewport {viewport_id:?}");
|
||||
let window_builder = egui_winit::create_winit_window_builder(
|
||||
&self.egui_ctx,
|
||||
event_loop,
|
||||
viewport.builder.clone(),
|
||||
);
|
||||
if window_builder.transparent() && self.gl_config.supports_transparency() == Some(false)
|
||||
{
|
||||
log::error!("Cannot create transparent window: the GL config does not support it");
|
||||
}
|
||||
let window =
|
||||
glutin_winit::finalize_window(event_loop, window_builder, &self.gl_config)?;
|
||||
egui_winit::apply_viewport_builder_to_window(
|
||||
@@ -1031,7 +1032,20 @@ impl GlutinWindowContext {
|
||||
viewport.window.insert(Rc::new(window))
|
||||
};
|
||||
|
||||
{
|
||||
viewport.egui_winit.get_or_insert_with(|| {
|
||||
log::debug!("Initializing egui_winit for viewport {viewport_id:?}");
|
||||
egui_winit::State::new(
|
||||
self.egui_ctx.clone(),
|
||||
viewport_id,
|
||||
event_loop,
|
||||
Some(window.scale_factor() as f32),
|
||||
self.max_texture_side,
|
||||
)
|
||||
});
|
||||
|
||||
if viewport.gl_surface.is_none() {
|
||||
log::debug!("Creating a gl_surface for viewport {viewport_id:?}");
|
||||
|
||||
// surface attributes
|
||||
let (width_px, height_px): (u32, u32) = window.inner_size().into();
|
||||
let width_px = std::num::NonZeroU32::new(width_px.at_least(1)).unwrap();
|
||||
@@ -1071,24 +1085,14 @@ impl GlutinWindowContext {
|
||||
// we will reach this point only once in most platforms except android.
|
||||
// create window/surface/make context current once and just use them forever.
|
||||
|
||||
viewport.egui_winit.get_or_insert_with(|| {
|
||||
egui_winit::State::new(
|
||||
self.egui_ctx.clone(),
|
||||
viewport_id,
|
||||
event_loop,
|
||||
Some(window.scale_factor() as f32),
|
||||
self.max_texture_side,
|
||||
)
|
||||
});
|
||||
|
||||
viewport.gl_surface = Some(gl_surface);
|
||||
|
||||
self.current_gl_context = Some(current_gl_context);
|
||||
self.viewport_from_window
|
||||
.insert(window.id(), viewport.ids.this);
|
||||
self.window_from_viewport
|
||||
.insert(viewport.ids.this, window.id());
|
||||
}
|
||||
|
||||
self.viewport_from_window.insert(window.id(), viewport_id);
|
||||
self.window_from_viewport.insert(viewport_id, window.id());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1153,6 +1157,7 @@ impl GlutinWindowContext {
|
||||
|
||||
fn handle_viewport_output(
|
||||
&mut self,
|
||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||
egui_ctx: &egui::Context,
|
||||
viewport_output: ViewportIdMap<ViewportOutput>,
|
||||
) {
|
||||
@@ -1197,6 +1202,9 @@ impl GlutinWindowContext {
|
||||
}
|
||||
}
|
||||
|
||||
// Create windows for any new viewports:
|
||||
self.initialize_all_windows(event_loop);
|
||||
|
||||
// GC old viewports
|
||||
self.viewports
|
||||
.retain(|id, _| active_viewports_ids.contains(id));
|
||||
@@ -1295,10 +1303,12 @@ fn render_immediate_viewport(
|
||||
viewport_ui_cb,
|
||||
} = immediate_viewport;
|
||||
|
||||
let viewport_id = ids.this;
|
||||
|
||||
{
|
||||
let mut glutin = glutin.borrow_mut();
|
||||
|
||||
let viewport = initialize_or_update_viewport(
|
||||
initialize_or_update_viewport(
|
||||
egui_ctx,
|
||||
&mut glutin.viewports,
|
||||
ids,
|
||||
@@ -1308,17 +1318,18 @@ fn render_immediate_viewport(
|
||||
None,
|
||||
);
|
||||
|
||||
if viewport.gl_surface.is_none() {
|
||||
glutin
|
||||
.init_viewport(ids.this, event_loop)
|
||||
.expect("Failed to initialize window in egui::Context::show_viewport_immediate");
|
||||
if let Err(err) = glutin.initialize_window(viewport_id, event_loop) {
|
||||
log::error!(
|
||||
"Failed to initialize a window for immediate viewport {viewport_id:?}: {err}"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let input = {
|
||||
let mut glutin = glutin.borrow_mut();
|
||||
|
||||
let Some(viewport) = glutin.viewports.get_mut(&ids.this) else {
|
||||
let Some(viewport) = glutin.viewports.get_mut(&viewport_id) else {
|
||||
return;
|
||||
};
|
||||
let (Some(egui_winit), Some(window)) = (&mut viewport.egui_winit, &viewport.window) else {
|
||||
@@ -1362,7 +1373,7 @@ fn render_immediate_viewport(
|
||||
..
|
||||
} = &mut *glutin;
|
||||
|
||||
let Some(viewport) = viewports.get_mut(&ids.this) else {
|
||||
let Some(viewport) = viewports.get_mut(&viewport_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -1423,7 +1434,7 @@ fn render_immediate_viewport(
|
||||
|
||||
egui_winit.handle_platform_output(window, platform_output);
|
||||
|
||||
glutin.handle_viewport_output(egui_ctx, viewport_output);
|
||||
glutin.handle_viewport_output(event_loop, egui_ctx, viewport_output);
|
||||
}
|
||||
|
||||
#[cfg(feature = "__screenshot")]
|
||||
|
||||
Reference in New Issue
Block a user