use std::{ ffi::{c_void, CStr}, os::raw::{c_char, c_int}, }; use crate::{ internal::{ImVector, RawCast}, Io, ViewportFlags, }; /// Holds the information needed to enable multiple viewports. #[repr(C)] pub struct PlatformIo { pub(crate) platform_create_window: Option, pub(crate) platform_destroy_window: Option, pub(crate) platform_show_window: Option, pub(crate) platform_set_window_pos: Option, pub(crate) platform_get_window_pos: Option sys::ImVec2>, pub(crate) platform_set_window_size: Option, pub(crate) platform_get_window_size: Option sys::ImVec2>, pub(crate) platform_set_window_focus: Option, pub(crate) platform_get_window_focus: Option bool>, pub(crate) platform_get_window_minimized: Option bool>, pub(crate) platform_set_window_title: Option, pub(crate) platform_set_window_alpha: Option, pub(crate) platform_update_window: Option, pub(crate) platform_render_window: Option, pub(crate) platform_swap_buffers: Option, pub(crate) platform_get_window_dpi_scale: Option f32>, pub(crate) platform_on_changed_viewport: Option, pub(crate) platform_create_vk_surface: Option c_int>, pub(crate) renderer_create_window: Option, pub(crate) renderer_destroy_window: Option, pub(crate) renderer_set_window_size: Option, pub(crate) renderer_render_window: Option, pub(crate) renderer_swap_buffers: Option, /// Holds information about the available monitors. /// Should be initialized and updated by the [`PlatformViewportBackend`]. pub monitors: ImVector, pub(crate) viewports: ImVector<*mut Viewport>, } unsafe impl RawCast for PlatformIo {} #[test] #[cfg(test)] fn test_platform_io_memory_layout() { use std::mem; assert_eq!( mem::size_of::(), mem::size_of::() ); assert_eq!( mem::align_of::(), mem::align_of::() ); use sys::ImGuiPlatformIO; macro_rules! assert_field_offset { ($l:ident, $r:ident) => { assert_eq!( memoffset::offset_of!(PlatformIo, $l), memoffset::offset_of!(ImGuiPlatformIO, $r) ); }; } assert_field_offset!(platform_create_window, Platform_CreateWindow); assert_field_offset!(platform_destroy_window, Platform_DestroyWindow); assert_field_offset!(platform_show_window, Platform_ShowWindow); assert_field_offset!(platform_set_window_pos, Platform_SetWindowPos); assert_field_offset!(platform_get_window_pos, Platform_GetWindowPos); assert_field_offset!(platform_set_window_size, Platform_SetWindowSize); assert_field_offset!(platform_get_window_size, Platform_GetWindowSize); assert_field_offset!(platform_set_window_focus, Platform_SetWindowFocus); assert_field_offset!(platform_get_window_focus, Platform_GetWindowFocus); assert_field_offset!(platform_get_window_minimized, Platform_GetWindowMinimized); assert_field_offset!(platform_set_window_title, Platform_SetWindowTitle); assert_field_offset!(platform_set_window_alpha, Platform_SetWindowAlpha); assert_field_offset!(platform_update_window, Platform_UpdateWindow); assert_field_offset!(platform_render_window, Platform_RenderWindow); assert_field_offset!(platform_swap_buffers, Platform_SwapBuffers); assert_field_offset!(platform_get_window_dpi_scale, Platform_GetWindowDpiScale); assert_field_offset!(platform_on_changed_viewport, Platform_OnChangedViewport); assert_field_offset!(platform_create_vk_surface, Platform_CreateVkSurface); assert_field_offset!(renderer_create_window, Renderer_CreateWindow); assert_field_offset!(renderer_destroy_window, Renderer_DestroyWindow); assert_field_offset!(renderer_set_window_size, Renderer_SetWindowSize); assert_field_offset!(renderer_render_window, Renderer_RenderWindow); assert_field_offset!(renderer_swap_buffers, Renderer_SwapBuffers); assert_field_offset!(monitors, Monitors); assert_field_offset!(viewports, Viewports); } /// Trait holding functions needed when the platform integration supports viewports. /// /// Register it via [`Context::set_platform_backend()`](crate::context::Context::set_platform_backend()) pub trait PlatformViewportBackend: 'static { /// Called by imgui when a new [`Viewport`] is created. /// /// # Notes /// This function should initiate the creation of a platform window. /// The window should be invisible. fn create_window(&mut self, viewport: &mut Viewport); /// Called by imgui when a [`Viewport`] is about to be destroyed. /// /// # Notes /// This function should initiate the destruction of the platform window. fn destroy_window(&mut self, viewport: &mut Viewport); /// Called by imgui to make a [`Viewport`] visible. fn show_window(&mut self, viewport: &mut Viewport); /// Called by imgui to reposition a [`Viewport`]. /// /// # Notes /// `pos` specifies the position of the windows content area (excluding title bar etc.) fn set_window_pos(&mut self, viewport: &mut Viewport, pos: [f32; 2]); /// Called by imgui to get the position of a [`Viewport`]. /// /// # Notes /// You should return the position of the window's content area (excluding title bar etc.) fn get_window_pos(&mut self, viewport: &mut Viewport) -> [f32; 2]; /// Called by imgui to set the size of a [`Viewport`]. /// /// # Notes /// `size` specifies the size of the window's content area (excluding title bar etc.) fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]); /// Called by imgui to get the size of a [`Viewport`]. /// /// # Notes /// you should return the size of the window's content area (excluding title bar etc.) fn get_window_size(&mut self, viewport: &mut Viewport) -> [f32; 2]; /// Called by imgui to make a [`Viewport`] steal the focus. fn set_window_focus(&mut self, viewport: &mut Viewport); /// Called by imgui to query whether a [`Viewport`] is in focus. fn get_window_focus(&mut self, viewport: &mut Viewport) -> bool; /// Called by imgui to query whether a [`Viewport`] is minimized. fn get_window_minimized(&mut self, viewport: &mut Viewport) -> bool; /// Called by imgui to set a [`Viewport`] title. fn set_window_title(&mut self, viewport: &mut Viewport, title: &str); /// Called by imgui to set the opacity of an entire [`Viewport`]. /// /// If your backend does not support opactiy, it is safe to just do nothing in this function. fn set_window_alpha(&mut self, viewport: &mut Viewport, alpha: f32); fn update_window(&mut self, viewport: &mut Viewport); fn render_window(&mut self, viewport: &mut Viewport); fn swap_buffers(&mut self, viewport: &mut Viewport); fn create_vk_surface( &mut self, viewport: &mut Viewport, instance: u64, out_surface: &mut u64, ) -> i32; } /// Used to get the current Contexts [`PlatformViewportContext`]. fn get_platform_ctx() -> &'static mut PlatformViewportContext { unsafe { // should be safe as it is impossible to call any imgui function on a non-active context. &mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data as *mut PlatformViewportContext) } } /// Used to get the current Contexts [`RendererViewportContext`]. fn get_renderer_ctx() -> &'static mut RendererViewportContext { unsafe { // should be safe as it is impossible to call any imgui function on a non-active context. &mut *((*(sys::igGetIO() as *const Io)).backend_renderer_user_data as *mut RendererViewportContext) } } pub(crate) extern "C" fn platform_create_window(viewport: *mut Viewport) { let ctx = get_platform_ctx(); ctx.backend.create_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_destroy_window(viewport: *mut Viewport) { let ctx = get_platform_ctx(); ctx.backend.destroy_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_show_window(viewport: *mut Viewport) { let ctx = get_platform_ctx(); ctx.backend.show_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_set_window_pos(viewport: *mut Viewport, pos: sys::ImVec2) { let ctx = get_platform_ctx(); ctx.backend .set_window_pos(unsafe { &mut *viewport }, [pos.x, pos.y]); } pub(crate) extern "C" fn platform_get_window_pos( viewport: *mut Viewport, out_pos: *mut sys::ImVec2, ) { let ctx = get_platform_ctx(); let pos = ctx.backend.get_window_pos(unsafe { &mut *viewport }); unsafe { *out_pos = sys::ImVec2::new(pos[0], pos[1]); } } pub(crate) extern "C" fn platform_set_window_size(viewport: *mut Viewport, size: sys::ImVec2) { let ctx = get_platform_ctx(); ctx.backend .set_window_size(unsafe { &mut *viewport }, [size.x, size.y]); } pub(crate) extern "C" fn platform_get_window_size( viewport: *mut Viewport, out_size: *mut sys::ImVec2, ) { let ctx = get_platform_ctx(); let size = ctx.backend.get_window_size(unsafe { &mut *viewport }); unsafe { *out_size = sys::ImVec2::new(size[0], size[1]); } } pub(crate) extern "C" fn platform_set_window_focus(viewport: *mut Viewport) { let ctx = get_platform_ctx(); ctx.backend.set_window_focus(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_get_window_focus(viewport: *mut Viewport) -> bool { let ctx = get_platform_ctx(); ctx.backend.get_window_focus(unsafe { &mut *viewport }) } pub(crate) extern "C" fn platform_get_window_minimized(viewport: *mut Viewport) -> bool { let ctx = get_platform_ctx(); ctx.backend.get_window_minimized(unsafe { &mut *viewport }) } pub(crate) extern "C" fn platform_set_window_title(viewport: *mut Viewport, title: *const c_char) { let ctx = get_platform_ctx(); let title = unsafe { CStr::from_ptr(title).to_str().unwrap() }; ctx.backend .set_window_title(unsafe { &mut *viewport }, title); } pub(crate) extern "C" fn platform_set_window_alpha(viewport: *mut Viewport, alpha: f32) { let ctx = get_platform_ctx(); ctx.backend .set_window_alpha(unsafe { &mut *viewport }, alpha); } pub(crate) extern "C" fn platform_update_window(viewport: *mut Viewport) { let ctx = get_platform_ctx(); ctx.backend.update_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_render_window(viewport: *mut Viewport, _arg: *mut c_void) { let ctx = get_platform_ctx(); ctx.backend.render_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_swap_buffers(viewport: *mut Viewport, _arg: *mut c_void) { let ctx = get_platform_ctx(); ctx.backend.swap_buffers(unsafe { &mut *viewport }); } pub(crate) extern "C" fn platform_create_vk_surface( viewport: *mut Viewport, instance: u64, _arg: *const c_void, out_surface: *mut u64, ) -> c_int { let ctx = get_platform_ctx(); ctx.backend .create_vk_surface(unsafe { &mut *viewport }, instance, unsafe { &mut *out_surface }) } /// The default [`PlatformViewportBackend`], does nothing. pub(crate) struct DummyPlatformViewportBackend {} impl PlatformViewportBackend for DummyPlatformViewportBackend { fn create_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn destroy_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn show_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn set_window_pos(&mut self, _viewport: &mut Viewport, _pos: [f32; 2]) { unimplemented!() } fn get_window_pos(&mut self, _viewport: &mut Viewport) -> [f32; 2] { unimplemented!() } fn set_window_size(&mut self, _viewport: &mut Viewport, _size: [f32; 2]) { unimplemented!() } fn get_window_size(&mut self, _viewport: &mut Viewport) -> [f32; 2] { unimplemented!() } fn set_window_focus(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn get_window_focus(&mut self, _viewport: &mut Viewport) -> bool { unimplemented!() } fn get_window_minimized(&mut self, _viewport: &mut Viewport) -> bool { unimplemented!() } fn set_window_title(&mut self, _viewport: &mut Viewport, _title: &str) { unimplemented!() } fn set_window_alpha(&mut self, _viewport: &mut Viewport, _alpha: f32) { unimplemented!() } fn update_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn render_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn swap_buffers(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn create_vk_surface( &mut self, _viewport: &mut Viewport, _instance: u64, _out_surface: &mut u64, ) -> i32 { unimplemented!() } } /// Just holds a [`PlatformViewportBackend`]. pub(crate) struct PlatformViewportContext { pub(crate) backend: Box, } impl PlatformViewportContext { pub(crate) fn dummy() -> Self { Self { backend: Box::new(DummyPlatformViewportBackend {}), } } } /// Trait that holds optional functions for a rendering backend to support multiple viewports. /// /// It is completely fine to not use this Backend at all, as all functions are optional. pub trait RendererViewportBackend: 'static { /// Called after [`PlatformViewportBackend::create_window()`]. fn create_window(&mut self, viewport: &mut Viewport); /// Called before [`PlatformViewportBackend::destroy_window()`]. fn destroy_window(&mut self, viewport: &mut Viewport); /// Called after [`PlatformViewportBackend::set_window_size()`]. fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]); fn render_window(&mut self, viewport: &mut Viewport); fn swap_buffers(&mut self, viewport: &mut Viewport); } pub(crate) extern "C" fn renderer_create_window(viewport: *mut Viewport) { let ctx = get_renderer_ctx(); ctx.backend.create_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn renderer_destroy_window(viewport: *mut Viewport) { let ctx = get_renderer_ctx(); ctx.backend.destroy_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn renderer_set_window_size(viewport: *mut Viewport, size: sys::ImVec2) { let ctx = get_renderer_ctx(); ctx.backend .set_window_size(unsafe { &mut *viewport }, [size.x, size.y]); } pub(crate) extern "C" fn renderer_render_window(viewport: *mut Viewport, _arg: *mut c_void) { let ctx = get_renderer_ctx(); ctx.backend.render_window(unsafe { &mut *viewport }); } pub(crate) extern "C" fn renderer_swap_buffers(viewport: *mut Viewport, _arg: *mut c_void) { let ctx = get_renderer_ctx(); ctx.backend.swap_buffers(unsafe { &mut *viewport }); } /// The default [`RendererViewportBackend`], does nothing. pub(crate) struct DummyRendererViewportBackend {} impl RendererViewportBackend for DummyRendererViewportBackend { fn create_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn destroy_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn set_window_size(&mut self, _viewport: &mut Viewport, _size: [f32; 2]) { unimplemented!() } fn render_window(&mut self, _viewport: &mut Viewport) { unimplemented!() } fn swap_buffers(&mut self, _viewport: &mut Viewport) { unimplemented!() } } /// Just holds a [`RendererViewportBackend`]. pub(crate) struct RendererViewportContext { pub(crate) backend: Box, } impl RendererViewportContext { pub(crate) fn dummy() -> Self { Self { backend: Box::new(DummyRendererViewportBackend {}), } } } /// Describes an ImGui Viewport. #[repr(C)] pub struct Viewport { /// The unique ID of this Viewport. pub id: crate::Id, /// Flags that describe how the Viewport should behave. pub flags: ViewportFlags, pub pos: [f32; 2], pub size: [f32; 2], pub work_pos: [f32; 2], pub work_size: [f32; 2], pub dpi_scale: f32, pub(crate) parent_viewport_id: crate::Id, pub(crate) draw_data: *mut crate::DrawData, pub renderer_user_data: *mut c_void, pub platform_user_data: *mut c_void, pub platform_handle: *mut c_void, pub platform_handle_raw: *mut c_void, pub platform_window_created: bool, pub platform_request_move: bool, pub platform_request_resize: bool, pub platform_request_close: bool, } impl Viewport { /// Returns the draw data of the respective Viewport. pub fn draw_data(&self) -> &crate::DrawData { unsafe { &*self.draw_data } } } #[test] #[cfg(test)] fn test_viewport_memory_layout() { use std::mem; assert_eq!( mem::size_of::(), mem::size_of::() ); assert_eq!( mem::align_of::(), mem::align_of::() ); use sys::ImGuiViewport; macro_rules! assert_field_offset { ($l:ident, $r:ident) => { assert_eq!( memoffset::offset_of!(Viewport, $l), memoffset::offset_of!(ImGuiViewport, $r) ); }; } assert_field_offset!(id, ID); assert_field_offset!(flags, Flags); assert_field_offset!(pos, Pos); assert_field_offset!(size, Size); assert_field_offset!(work_pos, WorkPos); assert_field_offset!(work_size, WorkSize); assert_field_offset!(dpi_scale, DpiScale); assert_field_offset!(parent_viewport_id, ParentViewportId); assert_field_offset!(draw_data, DrawData); assert_field_offset!(renderer_user_data, RendererUserData); assert_field_offset!(platform_user_data, PlatformUserData); assert_field_offset!(platform_handle, PlatformHandle); assert_field_offset!(platform_handle_raw, PlatformHandleRaw); assert_field_offset!(platform_window_created, PlatformWindowCreated); assert_field_offset!(platform_request_move, PlatformRequestMove); assert_field_offset!(platform_request_resize, PlatformRequestResize); assert_field_offset!(platform_request_close, PlatformRequestClose); } /// Describes a monitor that can be used by ImGui. #[repr(C)] pub struct PlatformMonitor { /// Position of the monitor on the virtual desktop. pub main_pos: [f32; 2], /// Size of the monitor on the virtual desktop. pub main_size: [f32; 2], /// Working position of the monitor, should exclude task bar etc. /// /// Set to `main_pos` if not known. pub work_pos: [f32; 2], /// Working size of the monitor, should exclude task bar etc. /// /// Set to `work_size` if not known. pub work_size: [f32; 2], pub dpi_scale: f32, } #[test] #[cfg(test)] fn test_platform_monitor_memory_layout() { use std::mem; assert_eq!( mem::size_of::(), mem::size_of::() ); assert_eq!( mem::align_of::(), mem::align_of::() ); use sys::ImGuiPlatformMonitor; macro_rules! assert_field_offset { ($l:ident, $r:ident) => { assert_eq!( memoffset::offset_of!(PlatformMonitor, $l), memoffset::offset_of!(ImGuiPlatformMonitor, $r) ); }; } assert_field_offset!(main_pos, MainPos); assert_field_offset!(main_size, MainSize); assert_field_offset!(work_pos, WorkPos); assert_field_offset!(work_size, WorkSize); assert_field_offset!(dpi_scale, DpiScale); } extern "C" { pub(crate) fn ImGuiPlatformIO_Set_Platform_GetWindowPos( pio: *mut PlatformIo, func: extern "C" fn(*mut Viewport, *mut sys::ImVec2), ); pub(crate) fn ImGuiPlatformIO_Set_Platform_GetWindowSize( pio: *mut PlatformIo, func: extern "C" fn(*mut Viewport, *mut sys::ImVec2), ); }