mod window;
use std::error::Error;
use glutin::config::{Config, ConfigTemplateBuilder};
use glutin::display::{Display, DisplayApiPreference};
#[cfg(x11_platform)]
use glutin::platform::x11::X11GlConfigExt;
use glutin::prelude::*;
#[cfg(wgl_backend)]
use raw_window_handle::HasRawWindowHandle;
use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle};
pub use window::GlWindow;
use winit::error::OsError;
use winit::event_loop::EventLoopWindowTarget;
#[cfg(glx_backend)]
use winit::platform::x11::register_xlib_error_hook;
#[cfg(x11_platform)]
use winit::platform::x11::WindowBuilderExtX11;
use winit::window::{Window, WindowBuilder};
use crate::error::ErrorMessage;
#[cfg(all(not(egl_backend), not(glx_backend), not(wgl_backend), not(cgl_backend)))]
compile_error!("Please select at least one api backend");
#[derive(Default, Debug, Clone)]
pub struct DisplayBuilder
{
preference: ApiPreference,
window_builder: Option<WindowBuilder>
}
impl DisplayBuilder
{
pub fn new() -> Self
{
Default::default()
}
#[allow(dead_code)]
pub fn with_preference(mut self, preference: ApiPreference) -> Self
{
self.preference = preference;
self
}
pub fn with_window_builder(mut self, window_builder: Option<WindowBuilder>) -> Self
{
self.window_builder = window_builder;
self
}
pub fn build<T, Picker>(
mut self,
window_target: &EventLoopWindowTarget<T>,
template_builder: ConfigTemplateBuilder,
config_picker: Picker
) -> Result<(Option<Window>, Config), Box<dyn Error>>
where
Picker: FnOnce(Box<dyn Iterator<Item = Config> + '_>) -> Option<Config>
{
#[cfg(wgl_backend)]
let window = if let Some(wb) = self.window_builder.take() {
Some(wb.build(window_target)?)
} else {
None
};
#[cfg(wgl_backend)]
let raw_window_handle = window.as_ref().map(|window| window.raw_window_handle());
#[cfg(not(wgl_backend))]
let raw_window_handle = None;
let gl_display =
create_display(window_target, self.preference, raw_window_handle)?;
#[cfg(wgl_backend)]
let template_builder = if let Some(raw_window_handle) = raw_window_handle {
template_builder.compatible_with_native_window(raw_window_handle)
} else {
template_builder
};
let template = template_builder.build();
let gl_config = unsafe {
let configs = gl_display.find_configs(template)?;
config_picker(configs)
}
.ok_or_else(|| ErrorMessage::msg("No valid GL config"))?;
#[cfg(not(wgl_backend))]
let window = if let Some(wb) = self.window_builder.take() {
Some(finalize_window(window_target, wb, &gl_config)?)
} else {
None
};
Ok((window, gl_config))
}
}
fn create_display<T>(
window_target: &EventLoopWindowTarget<T>,
_api_preference: ApiPreference,
_raw_window_handle: Option<RawWindowHandle>
) -> Result<Display, Box<dyn Error>>
{
#[cfg(egl_backend)]
let _preference = DisplayApiPreference::Egl;
#[cfg(glx_backend)]
let _preference = DisplayApiPreference::Glx(Box::new(register_xlib_error_hook));
#[cfg(cgl_backend)]
let _preference = DisplayApiPreference::Cgl;
#[cfg(wgl_backend)]
let _preference = DisplayApiPreference::Wgl(_raw_window_handle);
#[cfg(all(egl_backend, glx_backend))]
let _preference = match _api_preference {
ApiPreference::PreferEgl => {
DisplayApiPreference::EglThenGlx(Box::new(register_xlib_error_hook))
}
ApiPreference::FallbackEgl => {
DisplayApiPreference::GlxThenEgl(Box::new(register_xlib_error_hook))
}
};
#[cfg(all(wgl_backend, egl_backend))]
let _preference = match _api_preference {
ApiPreference::PreferEgl => DisplayApiPreference::EglThenWgl(_raw_window_handle),
ApiPreference::FallbackEgl => DisplayApiPreference::WglThenEgl(_raw_window_handle)
};
unsafe {
Ok(Display::new(
window_target.raw_display_handle(),
_preference
)?)
}
}
pub fn finalize_window<T>(
window_target: &EventLoopWindowTarget<T>,
mut builder: WindowBuilder,
gl_config: &Config
) -> Result<Window, OsError>
{
if gl_config.supports_transparency() == Some(false) {
builder = builder.with_transparent(false);
}
#[cfg(x11_platform)]
let builder = if let Some(x11_visual) = gl_config.x11_visual() {
builder.with_x11_visual(x11_visual.visual_id() as _)
} else {
builder
};
builder.build(window_target)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ApiPreference
{
#[allow(dead_code)]
PreferEgl,
#[default]
FallbackEgl
}