use super::*;
#[derive(Clone, Debug)]
pub(super) struct ContextBinding {
raw: *mut sys::ImGuiContext,
alive: ContextAliveToken,
}
impl ContextBinding {
pub(super) fn capture(imgui: &Context) -> Self {
Self {
raw: imgui.as_raw(),
alive: imgui.alive_token(),
}
}
pub(super) fn assert_matches(&self, imgui: &Context, caller: &str) {
assert!(
self.alive.is_alive(),
"{caller} requires the captured Dear ImGui context to still be alive"
);
assert_eq!(
self.raw,
imgui.as_raw(),
"{caller} received a different Dear ImGui context than the one used during backend initialization"
);
}
pub(super) fn bind(&self, caller: &str) -> CurrentContextGuard {
assert!(
self.alive.is_alive(),
"{caller} requires the captured Dear ImGui context to still be alive"
);
assert!(
!self.raw.is_null(),
"{caller} requires a non-null Dear ImGui context"
);
unsafe { CurrentContextGuard::bind(self.raw) }
}
pub(super) fn bind_for_drop(&self) -> Option<CurrentContextGuard> {
if self.alive.is_alive() && !self.raw.is_null() {
Some(unsafe { CurrentContextGuard::bind(self.raw) })
} else {
None
}
}
#[cfg(any(feature = "opengl3-renderer", feature = "sdlrenderer3-renderer"))]
pub(super) fn assert_current_draw_data(&self, draw_data: &mut DrawData, caller: &str) {
let expected = unsafe { sys::igGetDrawData() as *mut sys::ImDrawData };
let actual = draw_data as *mut DrawData as *mut sys::ImDrawData;
assert_eq!(
expected, actual,
"{caller} received draw data that does not belong to the captured Dear ImGui context"
);
}
}
#[derive(Debug)]
pub(super) struct CurrentContextGuard {
previous: *mut sys::ImGuiContext,
restore: bool,
}
impl CurrentContextGuard {
pub(super) unsafe fn bind(raw: *mut sys::ImGuiContext) -> Self {
let previous = unsafe { sys::igGetCurrentContext() };
let restore = previous != raw;
if restore {
unsafe {
sys::igSetCurrentContext(raw);
}
}
Self { previous, restore }
}
}
impl Drop for CurrentContextGuard {
fn drop(&mut self) {
if self.restore {
unsafe {
sys::igSetCurrentContext(self.previous);
}
}
}
}
pub(super) fn with_context<R>(imgui: &mut Context, caller: &str, f: impl FnOnce() -> R) -> R {
let context = ContextBinding::capture(imgui);
let _guard = context.bind(caller);
f()
}
pub(super) mod ffi {
use super::*;
unsafe extern "C" {
pub fn ImGui_ImplSDL3_InitForOpenGL_Rust(
window: *mut sdl3_sys::video::SDL_Window,
sdl_gl_context: *mut c_void,
) -> bool;
pub fn ImGui_ImplSDL3_InitForVulkan_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_InitForD3D_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_InitForMetal_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_InitForSDLRenderer_Rust(
window: *mut sdl3_sys::video::SDL_Window,
renderer: *mut sdl3_sys::render::SDL_Renderer,
) -> bool;
pub fn ImGui_ImplSDL3_InitForSDLGPU_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_InitForOther_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_Shutdown_Rust();
pub fn ImGui_ImplSDL3_NewFrame_Rust();
pub fn ImGui_ImplSDL3_ProcessEvent_Rust(event: *const SDL_Event) -> bool;
pub fn ImGui_ImplSDL3_SetGamepadMode_AutoFirst_Rust();
pub fn ImGui_ImplSDL3_SetGamepadMode_AutoAll_Rust();
pub fn ImGui_ImplSDL3_SetGamepadMode_Manual_Rust(
manual_gamepads_array: *const *mut sdl3_sys::gamepad::SDL_Gamepad,
manual_gamepads_count: i32,
);
}
}
#[derive(Debug, thiserror::Error)]
pub enum Sdl3BackendError {
#[error("ImGui_ImplSDL3_InitForOpenGL returned false")]
Sdl3InitFailed,
#[error("ImGui_ImplOpenGL3_Init returned false")]
OpenGlInitFailed,
#[error("Invalid GLSL version string")]
InvalidGlslVersion,
#[error("ImGui_ImplSDLRenderer3_Init returned false")]
Renderer3InitFailed,
}
#[cfg(feature = "opengl3-renderer")]
pub(super) fn init_opengl3_impl(
glsl_version: *const std::ffi::c_char,
) -> Result<(), Sdl3BackendError> {
unsafe {
if !opengl3_backend::dear_imgui_backend_opengl3_init(glsl_version) {
ffi::ImGui_ImplSDL3_Shutdown_Rust();
return Err(Sdl3BackendError::OpenGlInitFailed);
}
}
Ok(())
}
pub(super) fn shutdown_platform_impl() {
unsafe {
ffi::ImGui_ImplSDL3_Shutdown_Rust();
}
}
#[cfg(feature = "opengl3-renderer")]
pub(super) fn shutdown_opengl3_impl() {
unsafe {
opengl3_backend::dear_imgui_backend_opengl3_shutdown();
ffi::ImGui_ImplSDL3_Shutdown_Rust();
}
}
#[cfg(feature = "sdlrenderer3-renderer")]
pub(super) fn shutdown_sdlrenderer3_impl() {
unsafe {
sdlrenderer3_backend::dear_imgui_backend_sdlrenderer3_shutdown();
ffi::ImGui_ImplSDL3_Shutdown_Rust();
}
}
#[cfg(feature = "opengl3-renderer")]
pub(super) fn new_frame_opengl3_impl() {
unsafe {
opengl3_backend::dear_imgui_backend_opengl3_new_frame();
ffi::ImGui_ImplSDL3_NewFrame_Rust();
}
}
pub(super) fn sdl3_new_frame_impl() {
unsafe {
ffi::ImGui_ImplSDL3_NewFrame_Rust();
}
}
#[cfg(feature = "sdlrenderer3-renderer")]
pub(super) fn new_frame_sdlrenderer3_impl() {
unsafe {
sdlrenderer3_backend::dear_imgui_backend_sdlrenderer3_new_frame();
ffi::ImGui_ImplSDL3_NewFrame_Rust();
}
}