#![deny(rust_2018_idioms)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(clippy::all)]
#![deny(missing_debug_implementations)]
#![deny(missing_docs)]
#![cfg_attr(clippy, deny(warnings))]
mod event_loop;
mod window;
use event_loop::GlutinEventLoop;
pub use window::GlWindow;
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::HasWindowHandle;
use raw_window_handle::RawWindowHandle;
use winit::error::OsError;
use winit::window::{Window, WindowAttributes};
#[cfg(glx_backend)]
use winit::platform::x11::register_xlib_error_hook;
#[cfg(x11_platform)]
use winit::platform::x11::WindowAttributesExtX11;
#[cfg(all(not(egl_backend), not(glx_backend), not(wgl_backend), not(cgl_backend)))]
compile_error!("Please select at least one api backend");
pub(crate) mod private {
pub trait Sealed {}
}
#[derive(Default, Debug, Clone)]
pub struct DisplayBuilder {
preference: ApiPreference,
window_attributes: Option<WindowAttributes>,
}
impl DisplayBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn with_preference(mut self, preference: ApiPreference) -> Self {
self.preference = preference;
self
}
pub fn with_window_attributes(mut self, window_attributes: Option<WindowAttributes>) -> Self {
self.window_attributes = window_attributes;
self
}
pub fn build<Picker>(
mut self,
event_loop: &impl GlutinEventLoop,
template_builder: ConfigTemplateBuilder,
config_picker: Picker,
) -> Result<(Option<Window>, Config), Box<dyn Error>>
where
Picker: FnOnce(Box<dyn Iterator<Item = Config> + '_>) -> Config,
{
#[cfg(wgl_backend)]
let window = if let Some(wa) = self.window_attributes.take() {
Some(event_loop.create_window(wa)?)
} else {
None
};
#[cfg(wgl_backend)]
let raw_window_handle = window
.as_ref()
.and_then(|window| window.window_handle().ok())
.map(|handle| handle.as_raw());
#[cfg(not(wgl_backend))]
let raw_window_handle = None;
let gl_display = create_display(event_loop, 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)
};
#[cfg(not(wgl_backend))]
let window = if let Some(wa) = self.window_attributes.take() {
Some(finalize_window(event_loop, wa, &gl_config)?)
} else {
None
};
Ok((window, gl_config))
}
}
fn create_display(
event_loop: &impl GlutinEventLoop,
_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),
};
let handle = event_loop.glutin_display_handle()?.as_raw();
unsafe { Ok(Display::new(handle, _preference)?) }
}
pub fn finalize_window(
event_loop: &impl GlutinEventLoop,
mut attributes: WindowAttributes,
gl_config: &Config,
) -> Result<Window, OsError> {
if gl_config.supports_transparency() == Some(false) {
attributes = attributes.with_transparent(false);
}
#[cfg(x11_platform)]
let attributes = if let Some(x11_visual) = gl_config.x11_visual() {
attributes.with_x11_visual(x11_visual.visual_id() as _)
} else {
attributes
};
event_loop.create_window(attributes)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ApiPreference {
PreferEgl,
#[default]
FallbackEgl,
}