Skip to content

Commit

Permalink
egui-winit: don't assume window available at init
Browse files Browse the repository at this point in the history
On Android in particular we can only initialize render state once we
have a native window, after a 'Resumed' lifecycle event. It's still
practical to be able to initialize an egui_winit::State early on
so this adds setters for the max_texture_side and pixels_per_point
that can be called once we have a valid Window and have initialized
a graphics context.

On Wayland, where we need to access the Display for clipboard handling
we now get the Display from the event loop instead of a window.
  • Loading branch information
rib committed May 17, 2022
1 parent f807a29 commit b606b1f
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 34 deletions.
15 changes: 13 additions & 2 deletions eframe/src/native/epi_integration.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{epi, WindowInfo};
use egui_winit::{native_pixels_per_point, WindowSettings};
use winit::event_loop::EventLoopWindowTarget;

pub fn points_to_size(points: egui::Vec2) -> winit::dpi::LogicalSize<f64> {
winit::dpi::LogicalSize {
Expand Down Expand Up @@ -181,7 +182,8 @@ pub struct EpiIntegration {
}

impl EpiIntegration {
pub fn new(
pub fn new<E>(
event_loop: &EventLoopWindowTarget<E>,
max_texture_side: usize,
window: &winit::window::Window,
storage: Option<Box<dyn epi::Storage>>,
Expand All @@ -199,6 +201,7 @@ impl EpiIntegration {
prefer_dark_mode,
cpu_usage: None,
native_pixels_per_point: Some(native_pixels_per_point(window)),
// FIXME: this will panic on Android, before app 'Resumed'
window_info: read_window_info(window, egui_ctx.pixels_per_point()),
},
output: Default::default(),
Expand All @@ -213,11 +216,19 @@ impl EpiIntegration {
egui_ctx.set_visuals(egui::Visuals::light());
}

// TODO: enable Android support by not assuming we have a graphics context or that we
// have a valid Window at this stage.
let mut egui_winit = egui_winit::State::new(event_loop);
egui_winit.set_max_texture_side(max_texture_side);
// FIXME: this will panic on Android, before app 'Resumed'
let pixels_per_point = window.scale_factor() as f32;
egui_winit.set_pixels_per_point(pixels_per_point);

Self {
frame,
last_auto_save: std::time::Instant::now(),
egui_ctx,
egui_winit: egui_winit::State::new(max_texture_side, window),
egui_winit,
pending_full_output: Default::default(),
quit: false,
can_drag_window: false,
Expand Down
1 change: 1 addition & 0 deletions eframe/src/native/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub fn run_glow(
.unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error));

let mut integration = epi_integration::EpiIntegration::new(
&event_loop,
painter.max_texture_side(),
gl_window.window(),
storage,
Expand Down
1 change: 1 addition & 0 deletions egui-winit/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All notable changes to the `egui-winit` integration will be noted in this file.


## Unreleased
Allow deferred render + surface state initialization for Android ([#1633]()https://github.com/emilk/egui/issues/1633)


## 0.18.0 - 2022-04-30
Expand Down
59 changes: 32 additions & 27 deletions egui-winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ mod window_settings;

pub use window_settings::WindowSettings;

use winit::event_loop::EventLoopWindowTarget;
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
use winit::platform::unix::WindowExtUnix;
use winit::platform::unix::EventLoopWindowTargetExtUnix;

pub fn native_pixels_per_point(window: &winit::window::Window) -> f32 {
window.scale_factor() as f32
Expand Down Expand Up @@ -60,36 +61,18 @@ pub struct State {
}

impl State {
/// Initialize with:
/// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE`
/// * the native `pixels_per_point` (dpi scaling).
pub fn new(max_texture_side: usize, window: &winit::window::Window) -> Self {
Self::from_pixels_per_point(
max_texture_side,
native_pixels_per_point(window),
get_wayland_display(window),
)
pub fn new<T>(event_loop: &EventLoopWindowTarget<T>) -> Self {
Self::new_with_wayland_display(get_wayland_display(event_loop))
}

/// Initialize with:
/// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE`
/// * the given `pixels_per_point` (dpi scaling).
pub fn from_pixels_per_point(
max_texture_side: usize,
pixels_per_point: f32,
wayland_display: Option<*mut c_void>,
) -> Self {
pub fn new_with_wayland_display(wayland_display: Option<*mut c_void>) -> Self {
Self {
start_time: instant::Instant::now(),
egui_input: egui::RawInput {
pixels_per_point: Some(pixels_per_point),
max_texture_side: Some(max_texture_side),
..Default::default()
},
egui_input: Default::default(),
pointer_pos_in_points: None,
any_pointer_button_down: false,
current_cursor_icon: egui::CursorIcon::Default,
current_pixels_per_point: pixels_per_point,
current_pixels_per_point: 1.0,

clipboard: clipboard::Clipboard::new(wayland_display),
screen_reader: screen_reader::ScreenReader::default(),
Expand All @@ -99,6 +82,25 @@ impl State {
}
}

/// Call this once a graphics context has been created to update the maximum texture dimensions
/// that egui will use.
pub fn set_max_texture_side(&mut self, max_texture_side: usize) {
self.egui_input.max_texture_side = Some(max_texture_side);
}

/// Call this when a new native Window is created for rendering to initialize the `pixels_per_point`
/// for that window.
///
/// In particular, on Android it is necessary to call this after each `Resumed` lifecycle
/// event, each time a new native window is created.
///
/// Once this has been initialized for a new window then this state will be maintained by handling
/// [`winit::event::WindowEvent::ScaleFactorChanged`] events.
pub fn set_pixels_per_point(&mut self, pixels_per_point: f32) {
self.egui_input.pixels_per_point = Some(pixels_per_point);
self.current_pixels_per_point = pixels_per_point;
}

/// The number of physical pixels per logical point,
/// as configured on the current egui context (see [`egui::Context::pixels_per_point`]).
#[inline]
Expand Down Expand Up @@ -679,7 +681,7 @@ fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option<winit::window::Curs
}

/// Returns a Wayland display handle if the target is running Wayland
fn get_wayland_display(window: &winit::window::Window) -> Option<*mut c_void> {
fn get_wayland_display<T>(event_loop: &EventLoopWindowTarget<T>) -> Option<*mut c_void> {
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
Expand All @@ -688,11 +690,14 @@ fn get_wayland_display(window: &winit::window::Window) -> Option<*mut c_void> {
target_os = "openbsd"
))]
{
return window.wayland_display();
return event_loop.wayland_display();
}

#[allow(unreachable_code)]
None
{
let _ = event_loop;
None
}
}

// ---------------------------------------------------------------------------
Expand Down
16 changes: 11 additions & 5 deletions egui_glium/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#![allow(clippy::manual_range_contains)]

mod painter;
use egui_winit::winit::event_loop::EventLoopWindowTarget;
pub use painter::Painter;

pub use egui_winit;
Expand All @@ -25,14 +26,19 @@ pub struct EguiGlium {
}

impl EguiGlium {
pub fn new(display: &glium::Display) -> Self {
pub fn new<E>(display: &glium::Display, event_loop: &EventLoopWindowTarget<E>) -> Self {
let painter = crate::Painter::new(display);

// TODO: enable Android support by not assuming we have a graphics context or that we
// have a valid Window at this stage.
let mut egui_winit = egui_winit::State::new(event_loop);
egui_winit.set_max_texture_side(painter.max_texture_side());
let pixels_per_point = display.gl_window().window().scale_factor() as f32;
egui_winit.set_pixels_per_point(pixels_per_point);

Self {
egui_ctx: Default::default(),
egui_winit: egui_winit::State::new(
painter.max_texture_side(),
display.gl_window().window(),
),
egui_winit,
painter,
shapes: Default::default(),
textures_delta: Default::default(),
Expand Down

0 comments on commit b606b1f

Please sign in to comment.