mirror of
https://github.com/emilk/egui.git
synced 2026-09-03 07:10:04 -04:00
create_viewport_sync prep Glutin
WGPU Unimplemented again, use Arc<RwLock<T>> for a lot of things
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
//! Note that this file contains two similar paths - one for [`glow`], one for [`wgpu`].
|
||||
//! When making changes to one you often also want to apply it to the other.
|
||||
|
||||
use std::time::Instant;
|
||||
use std::{sync::Arc, time::Instant};
|
||||
|
||||
use egui::{epaint::ahash::HashMap, window::ViewportBuilder};
|
||||
use egui::{epaint::ahash::HashMap, mutex::RwLock, window::ViewportBuilder};
|
||||
use raw_window_handle::{HasRawDisplayHandle as _, HasRawWindowHandle as _};
|
||||
use winit::{
|
||||
event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget},
|
||||
@@ -72,9 +72,12 @@ trait WinitApp {
|
||||
|
||||
fn is_focused(&self, window_id: winit::window::WindowId) -> bool;
|
||||
|
||||
fn integration(&self) -> Option<&EpiIntegration>;
|
||||
fn integration(&self) -> Option<Arc<RwLock<EpiIntegration>>>;
|
||||
|
||||
fn window(&self, window_id: winit::window::WindowId) -> Option<&winit::window::Window>;
|
||||
fn window(
|
||||
&self,
|
||||
window_id: winit::window::WindowId,
|
||||
) -> Option<Arc<RwLock<winit::window::Window>>>;
|
||||
|
||||
fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId>;
|
||||
fn get_window_id(&self, id: &winit::window::WindowId) -> Option<u64>;
|
||||
@@ -248,7 +251,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) {
|
||||
window.request_redraw();
|
||||
window.read().request_redraw();
|
||||
windows_next_repaint_times.remove(window_id);
|
||||
control_flow.set_poll();
|
||||
} else {
|
||||
@@ -387,7 +390,7 @@ fn run_and_exit(event_loop: EventLoop<UserEvent>, mut winit_app: impl WinitApp +
|
||||
if *repaint_time <= Instant::now() {
|
||||
if let Some(window) = winit_app.window(*window_id) {
|
||||
log::trace!("request_redraw");
|
||||
window.request_redraw();
|
||||
window.read().request_redraw();
|
||||
windows_next_repaint_times.remove(window_id);
|
||||
}
|
||||
control_flow.set_poll();
|
||||
@@ -416,7 +419,9 @@ fn run_and_exit(event_loop: EventLoop<UserEvent>, mut winit_app: impl WinitApp +
|
||||
mod glow_integration {
|
||||
use std::sync::Arc;
|
||||
|
||||
use egui::{epaint::ahash::HashMap, window::ViewportBuilder, NumExt as _, ViewportRender};
|
||||
use egui::{
|
||||
epaint::ahash::HashMap, mutex::RwLock, window::ViewportBuilder, NumExt as _, ViewportRender,
|
||||
};
|
||||
use egui_winit::EventResponse;
|
||||
use glutin::{
|
||||
display::GetGlDisplay,
|
||||
@@ -446,17 +451,17 @@ mod glow_integration {
|
||||
struct GlowWinitRunning {
|
||||
gl: Arc<glow::Context>,
|
||||
painter: egui_glow::Painter,
|
||||
integration: epi_integration::EpiIntegration,
|
||||
integration: Arc<RwLock<epi_integration::EpiIntegration>>,
|
||||
app: Box<dyn epi::App>,
|
||||
// Conceptually this will be split out eventually so that the rest of the state
|
||||
// can be persistent.
|
||||
gl_window: GlutinWindowContext,
|
||||
glutin_ctx: Arc<RwLock<GlutinWindowContext>>,
|
||||
}
|
||||
|
||||
struct Window {
|
||||
builder: ViewportBuilder,
|
||||
gl_surface: Option<glutin::surface::Surface<glutin::surface::WindowSurface>>,
|
||||
window: Option<winit::window::Window>,
|
||||
window: Option<Arc<RwLock<winit::window::Window>>>,
|
||||
window_id: u64,
|
||||
parent_id: u64,
|
||||
render: Option<Arc<Box<ViewportRender>>>,
|
||||
@@ -478,9 +483,11 @@ mod glow_integration {
|
||||
struct GlutinWindowContext {
|
||||
swap_interval: glutin::surface::SwapInterval,
|
||||
gl_config: glutin::config::Config,
|
||||
|
||||
current_gl_context: Option<glutin::context::PossiblyCurrentContext>,
|
||||
not_current_gl_context: Option<glutin::context::NotCurrentContext>,
|
||||
windows: Vec<Window>,
|
||||
|
||||
windows: HashMap<u64, Arc<RwLock<Window>>>,
|
||||
window_maps: HashMap<winit::window::WindowId, u64>,
|
||||
}
|
||||
|
||||
@@ -592,6 +599,20 @@ mod glow_integration {
|
||||
window_maps.insert(window.id(), 0);
|
||||
}
|
||||
|
||||
let mut windows = HashMap::default();
|
||||
windows.insert(
|
||||
0,
|
||||
Arc::new(RwLock::new(Window {
|
||||
builder: window_builder,
|
||||
gl_surface: None,
|
||||
window: window.map(|w| Arc::new(RwLock::new(w))),
|
||||
window_id: 0,
|
||||
egui_winit: None,
|
||||
render: None,
|
||||
parent_id: 0,
|
||||
})),
|
||||
);
|
||||
|
||||
// the fun part with opengl gl is that we never know whether there is an error. the context creation might have failed, but
|
||||
// it could keep working until we try to make surface current or swap buffers or something else. future glutin improvements might
|
||||
// help us start from scratch again if we fail context creation and go back to preferEgl or try with different config etc..
|
||||
@@ -601,15 +622,7 @@ mod glow_integration {
|
||||
gl_config,
|
||||
current_gl_context: None,
|
||||
not_current_gl_context,
|
||||
windows: vec![Window {
|
||||
builder: window_builder,
|
||||
gl_surface: None,
|
||||
window,
|
||||
window_id: 0,
|
||||
egui_winit: None,
|
||||
render: None,
|
||||
parent_id: 0,
|
||||
}],
|
||||
windows,
|
||||
window_maps,
|
||||
})
|
||||
}
|
||||
@@ -624,7 +637,8 @@ mod glow_integration {
|
||||
/// we presently assume that we will
|
||||
#[allow(unsafe_code)]
|
||||
fn on_resume(&mut self, event_loop: &EventLoopWindowTarget<UserEvent>) -> Result<()> {
|
||||
for win in self.windows.iter_mut() {
|
||||
for (_, win) in self.windows.iter_mut() {
|
||||
let mut win = win.write();
|
||||
if win.gl_surface.is_some() {
|
||||
continue;
|
||||
}
|
||||
@@ -632,13 +646,17 @@ mod glow_integration {
|
||||
// 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");
|
||||
Arc::new(RwLock::new(
|
||||
glutin_winit::finalize_window(
|
||||
event_loop,
|
||||
create_winit_window_builder(&win.builder),
|
||||
&self.gl_config,
|
||||
)
|
||||
.expect("failed to finalize glutin window")
|
||||
.expect("failed to finalize glutin window"),
|
||||
))
|
||||
});
|
||||
{
|
||||
let window = window.read();
|
||||
// surface attributes
|
||||
let (width, height): (u32, u32) = window.inner_size().into();
|
||||
let width = std::num::NonZeroU32::new(width.at_least(1)).unwrap();
|
||||
@@ -657,7 +675,9 @@ mod glow_integration {
|
||||
.display()
|
||||
.create_window_surface(&self.gl_config, &surface_attributes)?
|
||||
};
|
||||
log::debug!("surface created successfully: {gl_surface:?}.making context current");
|
||||
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() {
|
||||
@@ -693,6 +713,7 @@ mod glow_integration {
|
||||
self.current_gl_context = Some(current_gl_context);
|
||||
self.window_maps.insert(window.id(), win.window_id);
|
||||
window.request_redraw();
|
||||
}
|
||||
win.window = Some(window);
|
||||
}
|
||||
Ok(())
|
||||
@@ -701,7 +722,8 @@ mod glow_integration {
|
||||
/// 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");
|
||||
for window in self.windows.iter_mut() {
|
||||
for (_, window) in self.windows.iter_mut() {
|
||||
let mut window = window.write();
|
||||
window.gl_surface.take();
|
||||
window.window.take();
|
||||
}
|
||||
@@ -714,18 +736,19 @@ mod glow_integration {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn window(&self, index: usize) -> &winit::window::Window {
|
||||
self.windows[index]
|
||||
.window
|
||||
.as_ref()
|
||||
fn window(&self, window_id: u64) -> Arc<RwLock<Window>> {
|
||||
self.windows
|
||||
.get(&window_id)
|
||||
.map(|w| w.clone())
|
||||
.expect("winit window doesn't exist")
|
||||
}
|
||||
|
||||
fn resize(&mut self, window_id: u64, physical_size: winit::dpi::PhysicalSize<u32>) {
|
||||
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();
|
||||
for window in self.windows.iter_mut() {
|
||||
if window.window_id == window_id {
|
||||
|
||||
if let Some(window) = self.windows.get(&window_id) {
|
||||
let mut window = window.write();
|
||||
if let Some(gl_surface) = &window.gl_surface {
|
||||
self.current_gl_context = Some(
|
||||
self.current_gl_context
|
||||
@@ -746,7 +769,6 @@ mod glow_integration {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_proc_address(&self, addr: &std::ffi::CStr) -> *const std::ffi::c_void {
|
||||
self.gl_config.display().get_proc_address(addr)
|
||||
@@ -757,13 +779,13 @@ mod glow_integration {
|
||||
repaint_proxy: Arc<egui::mutex::Mutex<EventLoopProxy<UserEvent>>>,
|
||||
app_name: String,
|
||||
native_options: epi::NativeOptions,
|
||||
running: Option<GlowWinitRunning>,
|
||||
running: Arc<RwLock<Option<GlowWinitRunning>>>,
|
||||
|
||||
// Note that since this `AppCreator` is FnOnce we are currently unable to support
|
||||
// re-initializing the `GlowWinitRunning` state on Android if the application
|
||||
// suspends and resumes.
|
||||
app_creator: Option<epi::AppCreator>,
|
||||
is_focused: Option<u64>,
|
||||
is_focused: Arc<RwLock<Option<u64>>>,
|
||||
}
|
||||
|
||||
impl GlowWinitApp {
|
||||
@@ -777,9 +799,9 @@ mod glow_integration {
|
||||
repaint_proxy: Arc::new(egui::mutex::Mutex::new(event_loop.create_proxy())),
|
||||
app_name: app_name.to_owned(),
|
||||
native_options,
|
||||
running: None,
|
||||
running: Arc::new(RwLock::new(None)),
|
||||
app_creator: Some(app_creator),
|
||||
is_focused: Some(0),
|
||||
is_focused: Arc::new(RwLock::new(Some(0))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,8 +823,11 @@ mod glow_integration {
|
||||
};
|
||||
glutin_window_context.on_resume(event_loop)?;
|
||||
|
||||
if let Some(window) = &glutin_window_context.windows[0].window {
|
||||
epi_integration::apply_native_options_to_window(window, native_options);
|
||||
if let Some(window) = &glutin_window_context.windows.get(&0) {
|
||||
let window = window.read();
|
||||
if let Some(window) = &window.window {
|
||||
epi_integration::apply_native_options_to_window(&window.read(), native_options);
|
||||
}
|
||||
}
|
||||
|
||||
let gl = unsafe {
|
||||
@@ -837,11 +862,14 @@ mod glow_integration {
|
||||
egui_glow::Painter::new(gl.clone(), "", self.native_options.shader_version)
|
||||
.unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error));
|
||||
|
||||
let system_theme = system_theme(gl_window.window(0), &self.native_options);
|
||||
let system_theme = system_theme(
|
||||
&gl_window.window(0).read().window.as_ref().unwrap().read(),
|
||||
&self.native_options,
|
||||
);
|
||||
let mut integration = epi_integration::EpiIntegration::new(
|
||||
event_loop,
|
||||
painter.max_texture_side(),
|
||||
gl_window.window(0),
|
||||
&gl_window.window(0).read().window.as_ref().unwrap().read(),
|
||||
system_theme,
|
||||
&self.app_name,
|
||||
&self.native_options,
|
||||
@@ -852,10 +880,11 @@ mod glow_integration {
|
||||
);
|
||||
#[cfg(feature = "accesskit")]
|
||||
{
|
||||
let window = &mut gl_window.windows[0];
|
||||
let window = gl_window.windows.get(&0).unwrap();
|
||||
let window = &mut *window.write();
|
||||
integration.init_accesskit(
|
||||
window.egui_winit.as_mut().unwrap(),
|
||||
window.window.as_ref().unwrap(),
|
||||
&window.window.as_ref().unwrap().read(),
|
||||
self.repaint_proxy.lock().clone(),
|
||||
);
|
||||
}
|
||||
@@ -868,9 +897,24 @@ mod glow_integration {
|
||||
|
||||
integration.egui_ctx.set_desktop(true);
|
||||
|
||||
gl_window.window(0).set_ime_allowed(true);
|
||||
gl_window
|
||||
.window(0)
|
||||
.read()
|
||||
.window
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.read()
|
||||
.set_ime_allowed(true);
|
||||
if self.native_options.mouse_passthrough {
|
||||
gl_window.window(0).set_cursor_hittest(false).unwrap();
|
||||
gl_window
|
||||
.window(0)
|
||||
.read()
|
||||
.window
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.read()
|
||||
.set_cursor_hittest(false)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
@@ -894,31 +938,35 @@ mod glow_integration {
|
||||
|
||||
let app_creator = std::mem::take(&mut self.app_creator)
|
||||
.expect("Single-use AppCreator has unexpectedly already been taken");
|
||||
let mut app = app_creator(&epi::CreationContext {
|
||||
let mut app;
|
||||
{
|
||||
let window = gl_window.window(0);
|
||||
let window = &mut *window.write();
|
||||
app = app_creator(&epi::CreationContext {
|
||||
egui_ctx: integration.egui_ctx.clone(),
|
||||
integration_info: integration.frame.info(),
|
||||
storage: integration.frame.storage(),
|
||||
gl: Some(gl.clone()),
|
||||
#[cfg(feature = "wgpu")]
|
||||
wgpu_render_state: None,
|
||||
raw_display_handle: gl_window.window(0).raw_display_handle(),
|
||||
raw_window_handle: gl_window.window(0).raw_window_handle(),
|
||||
raw_display_handle: window.window.as_ref().unwrap().read().raw_display_handle(),
|
||||
raw_window_handle: window.window.as_ref().unwrap().read().raw_window_handle(),
|
||||
});
|
||||
|
||||
if app.warm_up_enabled() {
|
||||
let window = &mut gl_window.windows[0];
|
||||
integration.warm_up(
|
||||
app.as_mut(),
|
||||
window.window.as_ref().unwrap(),
|
||||
&window.window.as_ref().unwrap().read(),
|
||||
window.egui_winit.as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.running = Some(GlowWinitRunning {
|
||||
gl_window,
|
||||
*self.running.write() = Some(GlowWinitRunning {
|
||||
glutin_ctx: Arc::new(RwLock::new(gl_window)),
|
||||
gl,
|
||||
painter,
|
||||
integration,
|
||||
integration: Arc::new(RwLock::new(integration)),
|
||||
app,
|
||||
});
|
||||
|
||||
@@ -929,31 +977,36 @@ mod glow_integration {
|
||||
impl WinitApp for GlowWinitApp {
|
||||
fn frame_nr(&self) -> u64 {
|
||||
self.running
|
||||
.read()
|
||||
.as_ref()
|
||||
.map_or(0, |r| r.integration.egui_ctx.frame_nr())
|
||||
.map_or(0, |r| r.integration.read().egui_ctx.frame_nr())
|
||||
}
|
||||
|
||||
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;
|
||||
if let Some(is_focused) = self.is_focused.read().as_ref() {
|
||||
if let Some(running) = self.running.read().as_ref() {
|
||||
if let Some(window_id) = running.glutin_ctx.read().window_maps.get(&window_id) {
|
||||
return *is_focused == *window_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn integration(&self) -> Option<&EpiIntegration> {
|
||||
self.running.as_ref().map(|r| &r.integration)
|
||||
fn integration(&self) -> Option<Arc<RwLock<EpiIntegration>>> {
|
||||
self.running.read().as_ref().map(|r| r.integration.clone())
|
||||
}
|
||||
|
||||
fn window(&self, window_id: winit::window::WindowId) -> Option<&winit::window::Window> {
|
||||
self.running.as_ref().and_then(|r| {
|
||||
for window in r.gl_window.windows.iter() {
|
||||
if let Some(window) = &window.window {
|
||||
if window.id() == window_id {
|
||||
return Some(window);
|
||||
fn window(
|
||||
&self,
|
||||
window_id: winit::window::WindowId,
|
||||
) -> Option<Arc<RwLock<winit::window::Window>>> {
|
||||
self.running.read().as_ref().and_then(|r| {
|
||||
let glutin_ctx = r.glutin_ctx.read();
|
||||
if let Some(viewport_id) = glutin_ctx.window_maps.get(&window_id) {
|
||||
if let Some(viewport) = glutin_ctx.windows.get(viewport_id) {
|
||||
if let Some(window) = viewport.read().window.as_ref() {
|
||||
return Some(window.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -962,68 +1015,63 @@ mod glow_integration {
|
||||
}
|
||||
|
||||
fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId> {
|
||||
self.running.as_ref().and_then(|r| {
|
||||
for window in r.gl_window.windows.iter() {
|
||||
if window.window_id == id {
|
||||
return window.window.as_ref().map(|w| w.id());
|
||||
}
|
||||
self.running.read().as_ref().and_then(|r| {
|
||||
if let Some(window) = r.glutin_ctx.read().windows.get(&id) {
|
||||
return window.read().window.as_ref().map(|w| w.read().id());
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
fn get_window_id(&self, id: &winit::window::WindowId) -> Option<u64> {
|
||||
self.running.as_ref().and_then(|r| {
|
||||
for window in r.gl_window.windows.iter() {
|
||||
if let Some(win) = &window.window {
|
||||
if win.id() == *id {
|
||||
return Some(window.window_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
self.running
|
||||
.read()
|
||||
.as_ref()
|
||||
.and_then(|r| r.glutin_ctx.read().window_maps.get(id).cloned())
|
||||
}
|
||||
|
||||
fn save_and_destroy(&mut self) {
|
||||
if let Some(mut running) = self.running.take() {
|
||||
running
|
||||
.integration
|
||||
.save(running.app.as_mut(), running.gl_window.window(0));
|
||||
if let Some(mut running) = self.running.write().take() {
|
||||
running.integration.write().save(
|
||||
running.app.as_mut(),
|
||||
&running
|
||||
.glutin_ctx
|
||||
.read()
|
||||
.window(0)
|
||||
.read()
|
||||
.window
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.read(),
|
||||
);
|
||||
running.app.on_exit(Some(&running.gl));
|
||||
running.painter.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> Vec<EventResult> {
|
||||
if let Some(running) = &mut self.running {
|
||||
let mut windows_indexes = vec![];
|
||||
for (i, window) in running.gl_window.windows.iter().enumerate() {
|
||||
if let Some(window) = &window.window {
|
||||
if window.id() == window_id {
|
||||
windows_indexes.push(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if self.running.read().is_none() {
|
||||
return vec![EventResult::Wait];
|
||||
}
|
||||
|
||||
let mut inner = |window_index| {
|
||||
if let Some(viewport_id) = self.get_window_id(&window_id) {
|
||||
#[cfg(feature = "puffin")]
|
||||
puffin::GlobalProfiler::lock().new_frame();
|
||||
crate::profile_scope!("frame");
|
||||
|
||||
let mut running = self.running.write();
|
||||
let GlowWinitRunning {
|
||||
gl_window,
|
||||
glutin_ctx: gl_window,
|
||||
gl,
|
||||
app,
|
||||
integration,
|
||||
painter,
|
||||
} = running;
|
||||
} = running.as_mut().unwrap();
|
||||
|
||||
let mut window_map = HashMap::default();
|
||||
for window in gl_window.windows.iter() {
|
||||
if let Some(win) = &window.window {
|
||||
window_map.insert(window.window_id, win.id());
|
||||
for (id, window) in gl_window.read().windows.iter() {
|
||||
if let Some(win) = &window.read().window {
|
||||
window_map.insert(*id, win.read().id());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1039,8 +1087,10 @@ mod glow_integration {
|
||||
let control_flow;
|
||||
{
|
||||
// let window = gl_window.window(window_index);
|
||||
let win: Option<&mut Window> = gl_window.windows.get_mut(window_index);
|
||||
let win = gl_window.read().windows.get(&viewport_id).cloned();
|
||||
let win = win.unwrap();
|
||||
{
|
||||
let mut gl_window = gl_window.write();
|
||||
gl_window.current_gl_context = Some(
|
||||
gl_window
|
||||
.current_gl_context
|
||||
@@ -1048,20 +1098,34 @@ mod glow_integration {
|
||||
.unwrap()
|
||||
.make_not_current()
|
||||
.unwrap()
|
||||
.make_current(win.gl_surface.as_ref().unwrap())
|
||||
.make_current(win.read().gl_surface.as_ref().unwrap())
|
||||
.unwrap(),
|
||||
);
|
||||
};
|
||||
|
||||
let screen_size_in_pixels: [u32; 2] =
|
||||
win.window.as_ref().unwrap().inner_size().into();
|
||||
let screen_size_in_pixels: [u32; 2] = win
|
||||
.read()
|
||||
.window
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.read()
|
||||
.inner_size()
|
||||
.into();
|
||||
|
||||
win.window.as_mut().unwrap().set_transparent(true);
|
||||
win.write()
|
||||
.window
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.read()
|
||||
.set_transparent(true);
|
||||
egui_glow::painter::clear(
|
||||
gl,
|
||||
screen_size_in_pixels,
|
||||
app.clear_color(&integration.egui_ctx.style().visuals),
|
||||
app.clear_color(&integration.read().egui_ctx.style().visuals),
|
||||
);
|
||||
|
||||
{
|
||||
let win = &mut *win.write();
|
||||
egui::FullOutput {
|
||||
platform_output,
|
||||
repaint_after,
|
||||
@@ -1069,33 +1133,35 @@ mod glow_integration {
|
||||
shapes,
|
||||
viewports,
|
||||
viewport_commands,
|
||||
} = integration.update(
|
||||
} = integration.write().update(
|
||||
app.as_mut(),
|
||||
win.window.as_ref().unwrap(),
|
||||
&win.window.as_ref().unwrap().read(),
|
||||
win.egui_winit.as_mut().unwrap(),
|
||||
win.render.clone(),
|
||||
win.window_id,
|
||||
win.parent_id,
|
||||
);
|
||||
|
||||
integration.handle_platform_output(
|
||||
win.window.as_ref().unwrap(),
|
||||
integration.write().handle_platform_output(
|
||||
&win.window.as_ref().unwrap().read(),
|
||||
platform_output,
|
||||
win.egui_winit.as_mut().unwrap(),
|
||||
);
|
||||
|
||||
}
|
||||
let clipped_primitives = {
|
||||
crate::profile_scope!("tessellate");
|
||||
integration.egui_ctx.tessellate(shapes)
|
||||
integration.read().egui_ctx.tessellate(shapes)
|
||||
};
|
||||
|
||||
painter.paint_and_update_textures(
|
||||
screen_size_in_pixels,
|
||||
integration.egui_ctx.pixels_per_point(),
|
||||
integration.read().egui_ctx.pixels_per_point(),
|
||||
&clipped_primitives,
|
||||
&textures_delta,
|
||||
);
|
||||
|
||||
let mut integration = integration.write();
|
||||
{
|
||||
let screenshot_requested =
|
||||
&mut integration.frame.output.screenshot_requested;
|
||||
|
||||
@@ -1105,22 +1171,29 @@ mod glow_integration {
|
||||
integration.frame.screenshot.set(Some(screenshot));
|
||||
}
|
||||
|
||||
integration.post_rendering(app.as_mut(), win.window.as_ref().unwrap());
|
||||
|
||||
{
|
||||
crate::profile_scope!("swap_buffers");
|
||||
let _ =
|
||||
win.gl_surface
|
||||
.as_ref()
|
||||
.expect("failed to get surface to swap buffers")
|
||||
.swap_buffers(
|
||||
gl_window.current_gl_context.as_ref().expect(
|
||||
"failed to get current context to swap buffers",
|
||||
),
|
||||
integration.post_rendering(
|
||||
app.as_mut(),
|
||||
&win.read().window.as_ref().unwrap().read(),
|
||||
);
|
||||
}
|
||||
|
||||
integration.post_present(win.window.as_ref().unwrap());
|
||||
{
|
||||
crate::profile_scope!("swap_buffers");
|
||||
let _ = win
|
||||
.read()
|
||||
.gl_surface
|
||||
.as_ref()
|
||||
.expect("failed to get surface to swap buffers")
|
||||
.swap_buffers(
|
||||
gl_window
|
||||
.read()
|
||||
.current_gl_context
|
||||
.as_ref()
|
||||
.expect("failed to get current context to swap buffers"),
|
||||
);
|
||||
}
|
||||
|
||||
integration.post_present(&win.read().window.as_ref().unwrap().read());
|
||||
|
||||
#[cfg(feature = "__screenshot")]
|
||||
// give it time to settle:
|
||||
@@ -1173,9 +1246,10 @@ mod glow_integration {
|
||||
.collect::<Vec<EventResult>>()
|
||||
};
|
||||
|
||||
integration.maybe_autosave(app.as_mut(), win.window.as_ref().unwrap());
|
||||
integration
|
||||
.maybe_autosave(app.as_mut(), &win.read().window.as_ref().unwrap().read());
|
||||
|
||||
if win.window.as_ref().unwrap().is_minimized() == Some(true) {
|
||||
if win.read().window.as_ref().unwrap().read().is_minimized() == Some(true) {
|
||||
// On Mac, a minimized Window uses up all CPU:
|
||||
// https://github.com/emilk/egui/issues/325
|
||||
crate::profile_scope!("bg_sleep");
|
||||
@@ -1187,11 +1261,11 @@ mod glow_integration {
|
||||
let mut active_viewports_ids = vec![0];
|
||||
|
||||
viewports.retain_mut(|(id, _, builder, render)| {
|
||||
for w in gl_window.windows.iter_mut() {
|
||||
if w.window_id == *id {
|
||||
if let Some(w) = gl_window.read().windows.get(id) {
|
||||
let mut w = w.write();
|
||||
if w.builder != *builder {
|
||||
if let Some(window) = &mut w.window {
|
||||
if let Ok(pos) = window.outer_position() {
|
||||
if let Ok(pos) = window.read().outer_position() {
|
||||
builder.position = Some((pos.x, pos.y));
|
||||
}
|
||||
}
|
||||
@@ -1202,14 +1276,16 @@ mod glow_integration {
|
||||
w.parent_id = *id;
|
||||
}
|
||||
active_viewports_ids.push(*id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
for (id, parent, builder, render) in viewports {
|
||||
gl_window.windows.push(Window {
|
||||
gl_window.write().windows.insert(
|
||||
id,
|
||||
Arc::new(RwLock::new(Window {
|
||||
builder,
|
||||
gl_surface: None,
|
||||
window: None,
|
||||
@@ -1217,19 +1293,21 @@ mod glow_integration {
|
||||
egui_winit: None,
|
||||
render: render.clone(),
|
||||
parent_id: parent,
|
||||
});
|
||||
})),
|
||||
);
|
||||
active_viewports_ids.push(id);
|
||||
}
|
||||
|
||||
// TODO Make this more efficient
|
||||
for (id, command) in viewport_commands {
|
||||
for window in gl_window.windows.iter() {
|
||||
if window.window_id == id {
|
||||
if let Some(window) = gl_window.read().windows.get(&id) {
|
||||
let window = window.read();
|
||||
|
||||
if let Some(win) = &window.window {
|
||||
let win = win.read();
|
||||
match command {
|
||||
egui::window::ViewportCommand::Drag => {
|
||||
// if this is not checked on x11 the input will be permanently taken until the app is killed!
|
||||
if let Some(focus) = self.is_focused {
|
||||
if let Some(focus) = self.is_focused.read().clone() {
|
||||
if focus == id {
|
||||
win.drag_window();
|
||||
}
|
||||
@@ -1238,68 +1316,34 @@ mod glow_integration {
|
||||
egui::window::ViewportCommand::InnerSize(width, height) => {
|
||||
win.set_inner_size(PhysicalSize::new(width, height));
|
||||
}
|
||||
egui::window::ViewportCommand::Resize(
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
left,
|
||||
) => {
|
||||
win.drag_resize_window(
|
||||
match (top, bottom, right, left) {
|
||||
(true, false, false, false) => {
|
||||
ResizeDirection::North
|
||||
}
|
||||
(false, true, false, false) => {
|
||||
ResizeDirection::South
|
||||
}
|
||||
(false, false, true, false) => {
|
||||
ResizeDirection::East
|
||||
}
|
||||
(false, false, false, true) => {
|
||||
ResizeDirection::West
|
||||
}
|
||||
(true, false, true, false) => {
|
||||
ResizeDirection::NorthEast
|
||||
}
|
||||
(false, true, true, false) => {
|
||||
ResizeDirection::SouthEast
|
||||
}
|
||||
(true, false, false, true) => {
|
||||
ResizeDirection::NorthWest
|
||||
}
|
||||
(false, true, false, true) => {
|
||||
ResizeDirection::SouthWest
|
||||
}
|
||||
egui::window::ViewportCommand::Resize(top, bottom, right, left) => {
|
||||
win.drag_resize_window(match (top, bottom, right, left) {
|
||||
(true, false, false, false) => ResizeDirection::North,
|
||||
(false, true, false, false) => ResizeDirection::South,
|
||||
(false, false, true, false) => ResizeDirection::East,
|
||||
(false, false, false, true) => ResizeDirection::West,
|
||||
(true, false, true, false) => ResizeDirection::NorthEast,
|
||||
(false, true, true, false) => ResizeDirection::SouthEast,
|
||||
(true, false, false, true) => ResizeDirection::NorthWest,
|
||||
(false, true, false, true) => ResizeDirection::SouthWest,
|
||||
_ => ResizeDirection::East,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gl_window
|
||||
.write()
|
||||
.windows
|
||||
.retain(|w| active_viewports_ids.contains(&w.window_id));
|
||||
.retain(|id, _| active_viewports_ids.contains(id));
|
||||
gl_window
|
||||
.write()
|
||||
.window_maps
|
||||
.retain(|_, id| active_viewports_ids.contains(id));
|
||||
|
||||
control_flow
|
||||
};
|
||||
|
||||
let mut events = vec![EventResult::Wait];
|
||||
|
||||
for event in windows_indexes
|
||||
.into_iter()
|
||||
.map(|window_index| inner(window_index))
|
||||
{
|
||||
events.extend(event)
|
||||
}
|
||||
events
|
||||
} else {
|
||||
vec![EventResult::Wait]
|
||||
}
|
||||
@@ -1315,33 +1359,55 @@ mod glow_integration {
|
||||
// first resume event.
|
||||
// we can actually move this outside of event loop.
|
||||
// and just run the on_resume fn of gl_window
|
||||
if self.running.is_none() {
|
||||
if self.running.read().is_none() {
|
||||
self.init_run_state(event_loop)?;
|
||||
} else {
|
||||
// not the first resume event. create whatever you need.
|
||||
self.running
|
||||
.write()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.gl_window
|
||||
.glutin_ctx
|
||||
.write()
|
||||
.on_resume(event_loop)?;
|
||||
}
|
||||
EventResult::RepaintNow(self.running.as_ref().unwrap().gl_window.window(0).id())
|
||||
EventResult::RepaintNow(
|
||||
self.running
|
||||
.read()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.glutin_ctx
|
||||
.read()
|
||||
.window(0)
|
||||
.read()
|
||||
.window
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.read()
|
||||
.id(),
|
||||
)
|
||||
}
|
||||
winit::event::Event::Suspended => {
|
||||
self.running.as_mut().unwrap().gl_window.on_suspend()?;
|
||||
self.running
|
||||
.write()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.glutin_ctx
|
||||
.write()
|
||||
.on_suspend()?;
|
||||
|
||||
EventResult::Wait
|
||||
}
|
||||
|
||||
winit::event::Event::MainEventsCleared => {
|
||||
if let Some(running) = self.running.as_mut() {
|
||||
let _ = running.gl_window.on_resume(event_loop);
|
||||
if let Some(running) = self.running.read().as_ref() {
|
||||
let _ = running.glutin_ctx.write().on_resume(event_loop);
|
||||
}
|
||||
EventResult::Wait
|
||||
}
|
||||
|
||||
winit::event::Event::WindowEvent { event, window_id } => {
|
||||
if let Some(running) = &mut self.running {
|
||||
if let Some(running) = self.running.write().as_mut() {
|
||||
// On Windows, if a window is resized by the user, it should repaint synchronously, inside the
|
||||
// event handler.
|
||||
//
|
||||
@@ -1359,8 +1425,15 @@ mod glow_integration {
|
||||
|
||||
match &event {
|
||||
winit::event::WindowEvent::Focused(new_focused) => {
|
||||
self.is_focused = new_focused
|
||||
.then(|| running.gl_window.window_maps.get(window_id).cloned())
|
||||
*self.is_focused.write() = new_focused
|
||||
.then(|| {
|
||||
running
|
||||
.glutin_ctx
|
||||
.write()
|
||||
.window_maps
|
||||
.get(window_id)
|
||||
.cloned()
|
||||
})
|
||||
.flatten();
|
||||
}
|
||||
winit::event::WindowEvent::Resized(physical_size) => {
|
||||
@@ -1369,9 +1442,10 @@ mod glow_integration {
|
||||
// Resize with 0 width and height is used by winit to signal a minimize event on Windows.
|
||||
// See: https://github.com/rust-windowing/winit/issues/208
|
||||
// This solves an issue where the app would panic when minimizing on Windows.
|
||||
let glutin_ctx = &mut *running.glutin_ctx.write();
|
||||
if physical_size.width > 0 && physical_size.height > 0 {
|
||||
if let Some(id) = running.gl_window.window_maps.get(window_id) {
|
||||
running.gl_window.resize(*id, *physical_size);
|
||||
if let Some(id) = glutin_ctx.window_maps.get(window_id) {
|
||||
glutin_ctx.resize(*id, *physical_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1379,20 +1453,23 @@ mod glow_integration {
|
||||
new_inner_size,
|
||||
..
|
||||
} => {
|
||||
let glutin_ctx = &mut *running.glutin_ctx.write();
|
||||
repaint_asap = true;
|
||||
if let Some(id) = running.gl_window.window_maps.get(window_id) {
|
||||
running.gl_window.resize(*id, **new_inner_size);
|
||||
if let Some(id) = glutin_ctx.window_maps.get(window_id) {
|
||||
glutin_ctx.resize(*id, **new_inner_size);
|
||||
}
|
||||
}
|
||||
winit::event::WindowEvent::CloseRequested
|
||||
if running
|
||||
.gl_window
|
||||
.glutin_ctx
|
||||
.write()
|
||||
.windows
|
||||
.iter()
|
||||
.flat_map(|window| {
|
||||
if let Some(win) = &window.window {
|
||||
.flat_map(|(_, window)| {
|
||||
if let Some(win) = window.read().window.as_ref() {
|
||||
let win = win.read();
|
||||
if win.id() == *window_id {
|
||||
Some(window.window_id)
|
||||
Some(window.read().window_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -1403,7 +1480,7 @@ mod glow_integration {
|
||||
.flat_map(|id| if id == 0 { Some(()) } else { None })
|
||||
.count()
|
||||
== 1
|
||||
&& running.integration.should_close() =>
|
||||
&& running.integration.read().should_close() =>
|
||||
{
|
||||
log::debug!("Received WindowEvent::CloseRequested");
|
||||
return Ok(EventResult::Exit);
|
||||
@@ -1412,24 +1489,32 @@ mod glow_integration {
|
||||
}
|
||||
|
||||
let event_response = 'res: {
|
||||
for window in running.gl_window.windows.iter_mut() {
|
||||
if window.window.as_ref().unwrap().id() == *window_id {
|
||||
break 'res running.integration.on_event(
|
||||
let glutin_ctx = running.glutin_ctx.read();
|
||||
if let Some(viewport_id) =
|
||||
glutin_ctx.window_maps.get(window_id).cloned()
|
||||
{
|
||||
if let Some(viewport) =
|
||||
glutin_ctx.windows.get(&viewport_id).cloned()
|
||||
{
|
||||
let viewport = &mut *viewport.write();
|
||||
|
||||
break 'res running.integration.write().on_event(
|
||||
running.app.as_mut(),
|
||||
event,
|
||||
window_id,
|
||||
window.egui_winit.as_mut().unwrap(),
|
||||
window.window_id,
|
||||
viewport.egui_winit.as_mut().unwrap(),
|
||||
viewport.window_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EventResponse {
|
||||
consumed: false,
|
||||
repaint: false,
|
||||
}
|
||||
};
|
||||
|
||||
if running.integration.should_close() {
|
||||
if running.integration.read().should_close() {
|
||||
EventResult::Exit
|
||||
} else if event_response.repaint {
|
||||
if repaint_asap {
|
||||
@@ -1448,20 +1533,21 @@ mod glow_integration {
|
||||
winit::event::Event::UserEvent(UserEvent::AccessKitActionRequest(
|
||||
accesskit_winit::ActionRequestEvent { request, window_id },
|
||||
)) => {
|
||||
if let Some(running) = &mut self.running {
|
||||
for window in running.gl_window.windows.iter_mut() {
|
||||
if window.window.as_ref().unwrap().id() == *window_id {
|
||||
running.integration.on_accesskit_action_request(
|
||||
if let Some(running) = self.running.read().as_ref() {
|
||||
let glutin_ctx = running.glutin_ctx.read();
|
||||
if let Some(viewport_id) = glutin_ctx.window_maps.get(window_id).cloned() {
|
||||
if let Some(viewport) = glutin_ctx.windows.get(&viewport_id).cloned() {
|
||||
let mut viewport = viewport.write();
|
||||
running.integration.write().on_accesskit_action_request(
|
||||
request.clone(),
|
||||
window_id,
|
||||
window.egui_winit.as_mut().unwrap(),
|
||||
);
|
||||
break;
|
||||
viewport.egui_winit.as_mut().unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
// As a form of user input, accessibility actions should
|
||||
// lead to a repaint.
|
||||
EventResult::RepaintNext(running.gl_window.window(0).id())
|
||||
EventResult::RepaintNext(*window_id)
|
||||
} else {
|
||||
EventResult::Wait
|
||||
}
|
||||
@@ -1726,16 +1812,21 @@ mod wgpu_integration {
|
||||
self.is_focused
|
||||
}
|
||||
|
||||
fn integration(&self) -> Option<&EpiIntegration> {
|
||||
self.running.as_ref().map(|r| &r.integration)
|
||||
fn integration(&self) -> Option<Arc<RwLock<EpiIntegration>>> {
|
||||
todo!()
|
||||
// self.running.as_ref().map(|r| r.integration)
|
||||
}
|
||||
|
||||
fn window(&self, window_id: winit::window::WindowId) -> Option<&winit::window::Window> {
|
||||
self.running
|
||||
.as_ref()
|
||||
.and_then(|r| r.windows_id.get(&window_id).map(|id| r.windows.get(id)))
|
||||
.flatten()
|
||||
.and_then(|w| w.0.as_ref())
|
||||
fn window(
|
||||
&self,
|
||||
window_id: winit::window::WindowId,
|
||||
) -> Option<Arc<RwLock<winit::window::Window>>> {
|
||||
todo!()
|
||||
// self.running
|
||||
// .as_ref()
|
||||
// .and_then(|r| r.windows_id.get(&window_id).map(|id| r.windows.get(id)))
|
||||
// .flatten()
|
||||
// .and_then(|w| w.0.as_ref())
|
||||
}
|
||||
|
||||
fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId> {
|
||||
|
||||
Reference in New Issue
Block a user