dear_imgui/
platform_io.rs

1//! Platform IO functionality for Dear ImGui
2//!
3//! This module provides access to Dear ImGui's platform IO system, which handles
4//! multi-viewport and platform-specific functionality.
5
6use crate::sys;
7#[cfg(feature = "multi-viewport")]
8use core::ffi::c_char;
9use std::ffi::c_void;
10#[cfg(feature = "multi-viewport")]
11use std::sync::Mutex;
12
13/// Platform IO structure for multi-viewport support
14///
15/// This is a transparent wrapper around `ImGuiPlatformIO` that provides
16/// safe access to platform-specific functionality.
17#[repr(transparent)]
18pub struct PlatformIo {
19    raw: sys::ImGuiPlatformIO,
20}
21
22// Typed-callback trampolines (avoid transmute) --------------------------------
23#[cfg(feature = "multi-viewport")]
24mod trampolines {
25    use super::*;
26    use core::ffi::c_char;
27
28    // Platform callbacks
29    pub static PLATFORM_CREATE_WINDOW_CB: Mutex<Option<unsafe extern "C" fn(*mut Viewport)>> =
30        Mutex::new(None);
31    pub static PLATFORM_DESTROY_WINDOW_CB: Mutex<Option<unsafe extern "C" fn(*mut Viewport)>> =
32        Mutex::new(None);
33    pub static PLATFORM_SHOW_WINDOW_CB: Mutex<Option<unsafe extern "C" fn(*mut Viewport)>> =
34        Mutex::new(None);
35    pub static PLATFORM_SET_WINDOW_POS_CB: Mutex<
36        Option<unsafe extern "C" fn(*mut Viewport, sys::ImVec2)>,
37    > = Mutex::new(None);
38    pub static PLATFORM_GET_WINDOW_POS_CB: Mutex<
39        Option<unsafe extern "C" fn(*mut Viewport) -> sys::ImVec2>,
40    > = Mutex::new(None);
41    pub static PLATFORM_SET_WINDOW_SIZE_CB: Mutex<
42        Option<unsafe extern "C" fn(*mut Viewport, sys::ImVec2)>,
43    > = Mutex::new(None);
44    pub static PLATFORM_GET_WINDOW_SIZE_CB: Mutex<
45        Option<unsafe extern "C" fn(*mut Viewport) -> sys::ImVec2>,
46    > = Mutex::new(None);
47    pub static PLATFORM_SET_WINDOW_FOCUS_CB: Mutex<Option<unsafe extern "C" fn(*mut Viewport)>> =
48        Mutex::new(None);
49    pub static PLATFORM_GET_WINDOW_FOCUS_CB: Mutex<
50        Option<unsafe extern "C" fn(*mut Viewport) -> bool>,
51    > = Mutex::new(None);
52    pub static PLATFORM_GET_WINDOW_MINIMIZED_CB: Mutex<
53        Option<unsafe extern "C" fn(*mut Viewport) -> bool>,
54    > = Mutex::new(None);
55    pub static PLATFORM_SET_WINDOW_TITLE_CB: Mutex<
56        Option<unsafe extern "C" fn(*mut Viewport, *const c_char)>,
57    > = Mutex::new(None);
58    pub static PLATFORM_SET_WINDOW_ALPHA_CB: Mutex<
59        Option<unsafe extern "C" fn(*mut Viewport, f32)>,
60    > = Mutex::new(None);
61    pub static PLATFORM_UPDATE_WINDOW_CB: Mutex<Option<unsafe extern "C" fn(*mut Viewport)>> =
62        Mutex::new(None);
63    pub static PLATFORM_RENDER_WINDOW_CB: Mutex<
64        Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
65    > = Mutex::new(None);
66    pub static PLATFORM_SWAP_BUFFERS_CB: Mutex<
67        Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
68    > = Mutex::new(None);
69
70    // Renderer callbacks
71    pub static RENDERER_CREATE_WINDOW_CB: Mutex<Option<unsafe extern "C" fn(*mut Viewport)>> =
72        Mutex::new(None);
73    pub static RENDERER_DESTROY_WINDOW_CB: Mutex<Option<unsafe extern "C" fn(*mut Viewport)>> =
74        Mutex::new(None);
75    pub static RENDERER_SET_WINDOW_SIZE_CB: Mutex<
76        Option<unsafe extern "C" fn(*mut Viewport, sys::ImVec2)>,
77    > = Mutex::new(None);
78    pub static RENDERER_RENDER_WINDOW_CB: Mutex<
79        Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
80    > = Mutex::new(None);
81    pub static RENDERER_SWAP_BUFFERS_CB: Mutex<
82        Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
83    > = Mutex::new(None);
84
85    // Trampolines for platform callbacks
86    pub unsafe extern "C" fn platform_create_window(vp: *mut sys::ImGuiViewport) {
87        if let Some(cb) = *PLATFORM_CREATE_WINDOW_CB.lock().unwrap() {
88            unsafe { cb(vp as *mut Viewport) }
89        }
90    }
91    pub unsafe extern "C" fn platform_destroy_window(vp: *mut sys::ImGuiViewport) {
92        if let Some(cb) = *PLATFORM_DESTROY_WINDOW_CB.lock().unwrap() {
93            unsafe { cb(vp as *mut Viewport) }
94        }
95    }
96    pub unsafe extern "C" fn platform_show_window(vp: *mut sys::ImGuiViewport) {
97        if let Some(cb) = *PLATFORM_SHOW_WINDOW_CB.lock().unwrap() {
98            unsafe { cb(vp as *mut Viewport) }
99        }
100    }
101    pub unsafe extern "C" fn platform_set_window_pos(vp: *mut sys::ImGuiViewport, p: sys::ImVec2) {
102        if let Some(cb) = *PLATFORM_SET_WINDOW_POS_CB.lock().unwrap() {
103            unsafe { cb(vp as *mut Viewport, p) }
104        }
105    }
106    pub unsafe extern "C" fn platform_get_window_pos(vp: *mut sys::ImGuiViewport) -> sys::ImVec2 {
107        if let Some(cb) = *PLATFORM_GET_WINDOW_POS_CB.lock().unwrap() {
108            return unsafe { cb(vp as *mut Viewport) };
109        }
110        sys::ImVec2 { x: 0.0, y: 0.0 }
111    }
112    pub unsafe extern "C" fn platform_set_window_size(vp: *mut sys::ImGuiViewport, s: sys::ImVec2) {
113        if let Some(cb) = *PLATFORM_SET_WINDOW_SIZE_CB.lock().unwrap() {
114            unsafe { cb(vp as *mut Viewport, s) }
115        }
116    }
117    pub unsafe extern "C" fn platform_get_window_size(vp: *mut sys::ImGuiViewport) -> sys::ImVec2 {
118        if let Some(cb) = *PLATFORM_GET_WINDOW_SIZE_CB.lock().unwrap() {
119            return unsafe { cb(vp as *mut Viewport) };
120        }
121        sys::ImVec2 { x: 0.0, y: 0.0 }
122    }
123    pub unsafe extern "C" fn platform_set_window_focus(vp: *mut sys::ImGuiViewport) {
124        if let Some(cb) = *PLATFORM_SET_WINDOW_FOCUS_CB.lock().unwrap() {
125            unsafe { cb(vp as *mut Viewport) }
126        }
127    }
128    pub unsafe extern "C" fn platform_get_window_focus(vp: *mut sys::ImGuiViewport) -> bool {
129        if let Some(cb) = *PLATFORM_GET_WINDOW_FOCUS_CB.lock().unwrap() {
130            return unsafe { cb(vp as *mut Viewport) };
131        }
132        false
133    }
134    pub unsafe extern "C" fn platform_get_window_minimized(vp: *mut sys::ImGuiViewport) -> bool {
135        if let Some(cb) = *PLATFORM_GET_WINDOW_MINIMIZED_CB.lock().unwrap() {
136            return unsafe { cb(vp as *mut Viewport) };
137        }
138        false
139    }
140    pub unsafe extern "C" fn platform_set_window_title(
141        vp: *mut sys::ImGuiViewport,
142        title: *const c_char,
143    ) {
144        if let Some(cb) = *PLATFORM_SET_WINDOW_TITLE_CB.lock().unwrap() {
145            unsafe { cb(vp as *mut Viewport, title) }
146        }
147    }
148    pub unsafe extern "C" fn platform_set_window_alpha(vp: *mut sys::ImGuiViewport, a: f32) {
149        if let Some(cb) = *PLATFORM_SET_WINDOW_ALPHA_CB.lock().unwrap() {
150            unsafe { cb(vp as *mut Viewport, a) }
151        }
152    }
153    pub unsafe extern "C" fn platform_update_window(vp: *mut sys::ImGuiViewport) {
154        if let Some(cb) = *PLATFORM_UPDATE_WINDOW_CB.lock().unwrap() {
155            unsafe { cb(vp as *mut Viewport) }
156        }
157    }
158    pub unsafe extern "C" fn platform_render_window(vp: *mut sys::ImGuiViewport, r: *mut c_void) {
159        if let Some(cb) = *PLATFORM_RENDER_WINDOW_CB.lock().unwrap() {
160            unsafe { cb(vp as *mut Viewport, r) }
161        }
162    }
163    pub unsafe extern "C" fn platform_swap_buffers(vp: *mut sys::ImGuiViewport, r: *mut c_void) {
164        if let Some(cb) = *PLATFORM_SWAP_BUFFERS_CB.lock().unwrap() {
165            unsafe { cb(vp as *mut Viewport, r) }
166        }
167    }
168
169    // Trampolines for renderer callbacks
170    pub unsafe extern "C" fn renderer_create_window(vp: *mut sys::ImGuiViewport) {
171        if let Some(cb) = *RENDERER_CREATE_WINDOW_CB.lock().unwrap() {
172            unsafe { cb(vp as *mut Viewport) }
173        }
174    }
175    pub unsafe extern "C" fn renderer_destroy_window(vp: *mut sys::ImGuiViewport) {
176        if let Some(cb) = *RENDERER_DESTROY_WINDOW_CB.lock().unwrap() {
177            unsafe { cb(vp as *mut Viewport) }
178        }
179    }
180    pub unsafe extern "C" fn renderer_set_window_size(vp: *mut sys::ImGuiViewport, s: sys::ImVec2) {
181        if let Some(cb) = *RENDERER_SET_WINDOW_SIZE_CB.lock().unwrap() {
182            unsafe { cb(vp as *mut Viewport, s) }
183        }
184    }
185    pub unsafe extern "C" fn renderer_render_window(vp: *mut sys::ImGuiViewport, r: *mut c_void) {
186        if let Some(cb) = *RENDERER_RENDER_WINDOW_CB.lock().unwrap() {
187            unsafe { cb(vp as *mut Viewport, r) }
188        }
189    }
190    pub unsafe extern "C" fn renderer_swap_buffers(vp: *mut sys::ImGuiViewport, r: *mut c_void) {
191        if let Some(cb) = *RENDERER_SWAP_BUFFERS_CB.lock().unwrap() {
192            unsafe { cb(vp as *mut Viewport, r) }
193        }
194    }
195}
196
197impl PlatformIo {
198    /// Get a reference to the platform IO from a raw pointer
199    ///
200    /// # Safety
201    ///
202    /// The caller must ensure that the pointer is valid and points to a valid
203    /// `ImGuiPlatformIO` structure.
204    pub(crate) unsafe fn from_raw(raw: *const sys::ImGuiPlatformIO) -> &'static Self {
205        unsafe { &*(raw as *const Self) }
206    }
207
208    /// Get a mutable reference to the platform IO from a raw pointer
209    ///
210    /// # Safety
211    ///
212    /// The caller must ensure that the pointer is valid and points to a valid
213    /// `ImGuiPlatformIO` structure, and that no other references exist.
214    pub unsafe fn from_raw_mut(raw: *mut sys::ImGuiPlatformIO) -> &'static mut Self {
215        unsafe { &mut *(raw as *mut Self) }
216    }
217
218    /// Get the raw pointer to the underlying `ImGuiPlatformIO`
219    pub fn as_raw(&self) -> *const sys::ImGuiPlatformIO {
220        &self.raw as *const _
221    }
222
223    /// Get the raw mutable pointer to the underlying `ImGuiPlatformIO`
224    pub fn as_raw_mut(&mut self) -> *mut sys::ImGuiPlatformIO {
225        &mut self.raw as *mut _
226    }
227
228    /// Set platform create window callback (raw sys pointer)
229    #[cfg(feature = "multi-viewport")]
230    pub fn set_platform_create_window_raw(
231        &mut self,
232        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport)>,
233    ) {
234        self.raw.Platform_CreateWindow = callback;
235    }
236
237    /// Set platform create window callback (typed Viewport). Unsafe due to FFI pointer cast.
238    #[cfg(feature = "multi-viewport")]
239    pub unsafe fn set_platform_create_window(
240        &mut self,
241        callback: Option<unsafe extern "C" fn(*mut Viewport)>,
242    ) {
243        use trampolines::*;
244        *PLATFORM_CREATE_WINDOW_CB.lock().unwrap() = callback;
245        self.set_platform_create_window_raw(callback.map(|_| {
246            trampolines::platform_create_window as unsafe extern "C" fn(*mut sys::ImGuiViewport)
247        }));
248    }
249
250    /// Set platform destroy window callback (raw)
251    #[cfg(feature = "multi-viewport")]
252    pub fn set_platform_destroy_window_raw(
253        &mut self,
254        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport)>,
255    ) {
256        self.raw.Platform_DestroyWindow = callback;
257    }
258
259    /// Set platform destroy window callback (typed). Unsafe due to FFI pointer cast.
260    #[cfg(feature = "multi-viewport")]
261    pub unsafe fn set_platform_destroy_window(
262        &mut self,
263        callback: Option<unsafe extern "C" fn(*mut Viewport)>,
264    ) {
265        use trampolines::*;
266        *PLATFORM_DESTROY_WINDOW_CB.lock().unwrap() = callback;
267        self.set_platform_destroy_window_raw(callback.map(|_| {
268            trampolines::platform_destroy_window as unsafe extern "C" fn(*mut sys::ImGuiViewport)
269        }));
270    }
271
272    /// Set platform show window callback (raw)
273    #[cfg(feature = "multi-viewport")]
274    pub fn set_platform_show_window_raw(
275        &mut self,
276        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport)>,
277    ) {
278        self.raw.Platform_ShowWindow = callback;
279    }
280
281    /// Set platform show window callback (typed). Unsafe due to FFI pointer cast.
282    #[cfg(feature = "multi-viewport")]
283    pub unsafe fn set_platform_show_window(
284        &mut self,
285        callback: Option<unsafe extern "C" fn(*mut Viewport)>,
286    ) {
287        use trampolines::*;
288        *PLATFORM_SHOW_WINDOW_CB.lock().unwrap() = callback;
289        self.set_platform_show_window_raw(callback.map(|_| {
290            trampolines::platform_show_window as unsafe extern "C" fn(*mut sys::ImGuiViewport)
291        }));
292    }
293
294    /// Set platform set window position callback (raw)
295    #[cfg(feature = "multi-viewport")]
296    pub fn set_platform_set_window_pos_raw(
297        &mut self,
298        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport, sys::ImVec2)>,
299    ) {
300        self.raw.Platform_SetWindowPos = callback;
301    }
302
303    /// Set platform set window position callback (typed). Unsafe due to FFI pointer cast.
304    #[cfg(feature = "multi-viewport")]
305    pub unsafe fn set_platform_set_window_pos(
306        &mut self,
307        callback: Option<unsafe extern "C" fn(*mut Viewport, sys::ImVec2)>,
308    ) {
309        use trampolines::*;
310        *PLATFORM_SET_WINDOW_POS_CB.lock().unwrap() = callback;
311        self.set_platform_set_window_pos_raw(callback.map(|_| {
312            trampolines::platform_set_window_pos
313                as unsafe extern "C" fn(*mut sys::ImGuiViewport, sys::ImVec2)
314        }));
315    }
316
317    /// Set platform get window position callback (raw)
318    #[cfg(feature = "multi-viewport")]
319    pub fn set_platform_get_window_pos_raw(
320        &mut self,
321        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport) -> sys::ImVec2>,
322    ) {
323        self.raw.Platform_GetWindowPos = callback;
324    }
325
326    /// Set platform get window position callback (typed). Unsafe due to FFI pointer cast.
327    #[cfg(feature = "multi-viewport")]
328    pub unsafe fn set_platform_get_window_pos(
329        &mut self,
330        callback: Option<unsafe extern "C" fn(*mut Viewport) -> sys::ImVec2>,
331    ) {
332        use trampolines::*;
333        *PLATFORM_GET_WINDOW_POS_CB.lock().unwrap() = callback;
334        self.set_platform_get_window_pos_raw(callback.map(|_| {
335            trampolines::platform_get_window_pos
336                as unsafe extern "C" fn(*mut sys::ImGuiViewport) -> sys::ImVec2
337        }));
338    }
339
340    /// Set platform set window size callback (raw)
341    #[cfg(feature = "multi-viewport")]
342    pub fn set_platform_set_window_size_raw(
343        &mut self,
344        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport, sys::ImVec2)>,
345    ) {
346        self.raw.Platform_SetWindowSize = callback;
347    }
348
349    /// Set platform set window size callback (typed). Unsafe due to FFI pointer cast.
350    #[cfg(feature = "multi-viewport")]
351    pub unsafe fn set_platform_set_window_size(
352        &mut self,
353        callback: Option<unsafe extern "C" fn(*mut Viewport, sys::ImVec2)>,
354    ) {
355        use trampolines::*;
356        *PLATFORM_SET_WINDOW_SIZE_CB.lock().unwrap() = callback;
357        self.set_platform_set_window_size_raw(callback.map(|_| {
358            trampolines::platform_set_window_size
359                as unsafe extern "C" fn(*mut sys::ImGuiViewport, sys::ImVec2)
360        }));
361    }
362
363    /// Set platform get window size callback (raw)
364    #[cfg(feature = "multi-viewport")]
365    pub fn set_platform_get_window_size_raw(
366        &mut self,
367        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport) -> sys::ImVec2>,
368    ) {
369        self.raw.Platform_GetWindowSize = callback;
370    }
371
372    /// Set platform get window size callback (typed). Unsafe due to FFI pointer cast.
373    #[cfg(feature = "multi-viewport")]
374    pub unsafe fn set_platform_get_window_size(
375        &mut self,
376        callback: Option<unsafe extern "C" fn(*mut Viewport) -> sys::ImVec2>,
377    ) {
378        use trampolines::*;
379        *PLATFORM_GET_WINDOW_SIZE_CB.lock().unwrap() = callback;
380        self.set_platform_get_window_size_raw(callback.map(|_| {
381            trampolines::platform_get_window_size
382                as unsafe extern "C" fn(*mut sys::ImGuiViewport) -> sys::ImVec2
383        }));
384    }
385
386    /// Set platform set window focus callback (raw)
387    #[cfg(feature = "multi-viewport")]
388    pub fn set_platform_set_window_focus_raw(
389        &mut self,
390        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport)>,
391    ) {
392        self.raw.Platform_SetWindowFocus = callback;
393    }
394
395    /// Set platform set window focus callback (typed). Unsafe due to FFI pointer cast.
396    #[cfg(feature = "multi-viewport")]
397    pub unsafe fn set_platform_set_window_focus(
398        &mut self,
399        callback: Option<unsafe extern "C" fn(*mut Viewport)>,
400    ) {
401        use trampolines::*;
402        *PLATFORM_SET_WINDOW_FOCUS_CB.lock().unwrap() = callback;
403        self.set_platform_set_window_focus_raw(callback.map(|_| {
404            trampolines::platform_set_window_focus as unsafe extern "C" fn(*mut sys::ImGuiViewport)
405        }));
406    }
407
408    /// Set platform get window focus callback (raw)
409    #[cfg(feature = "multi-viewport")]
410    pub fn set_platform_get_window_focus_raw(
411        &mut self,
412        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport) -> bool>,
413    ) {
414        self.raw.Platform_GetWindowFocus = callback;
415    }
416
417    /// Set platform get window focus callback (typed). Unsafe due to FFI pointer cast.
418    #[cfg(feature = "multi-viewport")]
419    pub unsafe fn set_platform_get_window_focus(
420        &mut self,
421        callback: Option<unsafe extern "C" fn(*mut Viewport) -> bool>,
422    ) {
423        use trampolines::*;
424        *PLATFORM_GET_WINDOW_FOCUS_CB.lock().unwrap() = callback;
425        self.set_platform_get_window_focus_raw(callback.map(|_| {
426            trampolines::platform_get_window_focus
427                as unsafe extern "C" fn(*mut sys::ImGuiViewport) -> bool
428        }));
429    }
430
431    /// Set platform get window minimized callback (raw)
432    #[cfg(feature = "multi-viewport")]
433    pub fn set_platform_get_window_minimized_raw(
434        &mut self,
435        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport) -> bool>,
436    ) {
437        self.raw.Platform_GetWindowMinimized = callback;
438    }
439
440    /// Set platform get window minimized callback (typed). Unsafe due to FFI pointer cast.
441    #[cfg(feature = "multi-viewport")]
442    pub unsafe fn set_platform_get_window_minimized(
443        &mut self,
444        callback: Option<unsafe extern "C" fn(*mut Viewport) -> bool>,
445    ) {
446        use trampolines::*;
447        *PLATFORM_GET_WINDOW_MINIMIZED_CB.lock().unwrap() = callback;
448        self.set_platform_get_window_minimized_raw(callback.map(|_| {
449            trampolines::platform_get_window_minimized
450                as unsafe extern "C" fn(*mut sys::ImGuiViewport) -> bool
451        }));
452    }
453
454    /// Set platform set window title callback (raw)
455    #[cfg(feature = "multi-viewport")]
456    pub fn set_platform_set_window_title_raw(
457        &mut self,
458        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport, *const c_char)>,
459    ) {
460        self.raw.Platform_SetWindowTitle = callback;
461    }
462
463    /// Set platform set window title callback (typed). Unsafe due to FFI pointer cast.
464    #[cfg(feature = "multi-viewport")]
465    pub unsafe fn set_platform_set_window_title(
466        &mut self,
467        callback: Option<unsafe extern "C" fn(*mut Viewport, *const c_char)>,
468    ) {
469        use trampolines::*;
470        *PLATFORM_SET_WINDOW_TITLE_CB.lock().unwrap() = callback;
471        self.set_platform_set_window_title_raw(callback.map(|_| {
472            trampolines::platform_set_window_title
473                as unsafe extern "C" fn(*mut sys::ImGuiViewport, *const c_char)
474        }));
475    }
476
477    /// Set platform set window alpha callback (raw)
478    #[cfg(feature = "multi-viewport")]
479    pub fn set_platform_set_window_alpha_raw(
480        &mut self,
481        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport, f32)>,
482    ) {
483        self.raw.Platform_SetWindowAlpha = callback;
484    }
485
486    /// Set platform set window alpha callback (typed). Unsafe due to FFI pointer cast.
487    #[cfg(feature = "multi-viewport")]
488    pub unsafe fn set_platform_set_window_alpha(
489        &mut self,
490        callback: Option<unsafe extern "C" fn(*mut Viewport, f32)>,
491    ) {
492        use trampolines::*;
493        *PLATFORM_SET_WINDOW_ALPHA_CB.lock().unwrap() = callback;
494        self.set_platform_set_window_alpha_raw(callback.map(|_| {
495            trampolines::platform_set_window_alpha
496                as unsafe extern "C" fn(*mut sys::ImGuiViewport, f32)
497        }));
498    }
499
500    /// Set platform update window callback (raw)
501    #[cfg(feature = "multi-viewport")]
502    pub fn set_platform_update_window_raw(
503        &mut self,
504        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport)>,
505    ) {
506        self.raw.Platform_UpdateWindow = callback;
507    }
508
509    /// Set platform update window callback (typed). Unsafe due to FFI pointer cast.
510    #[cfg(feature = "multi-viewport")]
511    pub unsafe fn set_platform_update_window(
512        &mut self,
513        callback: Option<unsafe extern "C" fn(*mut Viewport)>,
514    ) {
515        use trampolines::*;
516        *PLATFORM_UPDATE_WINDOW_CB.lock().unwrap() = callback;
517        self.set_platform_update_window_raw(callback.map(|_| {
518            trampolines::platform_update_window as unsafe extern "C" fn(*mut sys::ImGuiViewport)
519        }));
520    }
521
522    /// Set platform render window callback (raw)
523    #[cfg(feature = "multi-viewport")]
524    pub fn set_platform_render_window_raw(
525        &mut self,
526        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport, *mut c_void)>,
527    ) {
528        self.raw.Platform_RenderWindow = callback;
529    }
530
531    /// Set platform render window callback (typed). Unsafe due to FFI pointer cast.
532    #[cfg(feature = "multi-viewport")]
533    pub unsafe fn set_platform_render_window(
534        &mut self,
535        callback: Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
536    ) {
537        use trampolines::*;
538        *PLATFORM_RENDER_WINDOW_CB.lock().unwrap() = callback;
539        self.set_platform_render_window_raw(callback.map(|_| {
540            trampolines::platform_render_window
541                as unsafe extern "C" fn(*mut sys::ImGuiViewport, *mut c_void)
542        }));
543    }
544
545    /// Set platform swap buffers callback (raw)
546    #[cfg(feature = "multi-viewport")]
547    pub fn set_platform_swap_buffers_raw(
548        &mut self,
549        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport, *mut c_void)>,
550    ) {
551        self.raw.Platform_SwapBuffers = callback;
552    }
553
554    /// Set platform swap buffers callback (typed). Unsafe due to FFI pointer cast.
555    #[cfg(feature = "multi-viewport")]
556    pub unsafe fn set_platform_swap_buffers(
557        &mut self,
558        callback: Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
559    ) {
560        use trampolines::*;
561        *PLATFORM_SWAP_BUFFERS_CB.lock().unwrap() = callback;
562        self.set_platform_swap_buffers_raw(callback.map(|_| {
563            trampolines::platform_swap_buffers
564                as unsafe extern "C" fn(*mut sys::ImGuiViewport, *mut c_void)
565        }));
566    }
567
568    /// Set renderer create window callback (raw)
569    #[cfg(feature = "multi-viewport")]
570    pub fn set_renderer_create_window_raw(
571        &mut self,
572        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport)>,
573    ) {
574        self.raw.Renderer_CreateWindow = callback;
575    }
576
577    /// Set renderer create window callback (typed). Unsafe due to FFI pointer cast.
578    #[cfg(feature = "multi-viewport")]
579    pub unsafe fn set_renderer_create_window(
580        &mut self,
581        callback: Option<unsafe extern "C" fn(*mut Viewport)>,
582    ) {
583        use trampolines::*;
584        *RENDERER_CREATE_WINDOW_CB.lock().unwrap() = callback;
585        self.set_renderer_create_window_raw(callback.map(|_| {
586            trampolines::renderer_create_window as unsafe extern "C" fn(*mut sys::ImGuiViewport)
587        }));
588    }
589
590    /// Set renderer destroy window callback (raw)
591    #[cfg(feature = "multi-viewport")]
592    pub fn set_renderer_destroy_window_raw(
593        &mut self,
594        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport)>,
595    ) {
596        self.raw.Renderer_DestroyWindow = callback;
597    }
598
599    /// Set renderer destroy window callback (typed). Unsafe due to FFI pointer cast.
600    #[cfg(feature = "multi-viewport")]
601    pub unsafe fn set_renderer_destroy_window(
602        &mut self,
603        callback: Option<unsafe extern "C" fn(*mut Viewport)>,
604    ) {
605        use trampolines::*;
606        *RENDERER_DESTROY_WINDOW_CB.lock().unwrap() = callback;
607        self.set_renderer_destroy_window_raw(callback.map(|_| {
608            trampolines::renderer_destroy_window as unsafe extern "C" fn(*mut sys::ImGuiViewport)
609        }));
610    }
611
612    /// Set renderer set window size callback (raw)
613    #[cfg(feature = "multi-viewport")]
614    pub fn set_renderer_set_window_size_raw(
615        &mut self,
616        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport, sys::ImVec2)>,
617    ) {
618        self.raw.Renderer_SetWindowSize = callback;
619    }
620
621    /// Set renderer set window size callback (typed). Unsafe due to FFI pointer cast.
622    #[cfg(feature = "multi-viewport")]
623    pub unsafe fn set_renderer_set_window_size(
624        &mut self,
625        callback: Option<unsafe extern "C" fn(*mut Viewport, sys::ImVec2)>,
626    ) {
627        use trampolines::*;
628        *RENDERER_SET_WINDOW_SIZE_CB.lock().unwrap() = callback;
629        self.set_renderer_set_window_size_raw(callback.map(|_| {
630            trampolines::renderer_set_window_size
631                as unsafe extern "C" fn(*mut sys::ImGuiViewport, sys::ImVec2)
632        }));
633    }
634
635    /// Set renderer render window callback (raw)
636    #[cfg(feature = "multi-viewport")]
637    pub fn set_renderer_render_window_raw(
638        &mut self,
639        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport, *mut c_void)>,
640    ) {
641        self.raw.Renderer_RenderWindow = callback;
642    }
643
644    /// Set renderer render window callback (typed). Unsafe due to FFI pointer cast.
645    #[cfg(feature = "multi-viewport")]
646    pub unsafe fn set_renderer_render_window(
647        &mut self,
648        callback: Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
649    ) {
650        use trampolines::*;
651        *RENDERER_RENDER_WINDOW_CB.lock().unwrap() = callback;
652        self.set_renderer_render_window_raw(callback.map(|_| {
653            trampolines::renderer_render_window
654                as unsafe extern "C" fn(*mut sys::ImGuiViewport, *mut c_void)
655        }));
656    }
657
658    /// Set renderer swap buffers callback (raw)
659    #[cfg(feature = "multi-viewport")]
660    pub fn set_renderer_swap_buffers_raw(
661        &mut self,
662        callback: Option<unsafe extern "C" fn(*mut sys::ImGuiViewport, *mut c_void)>,
663    ) {
664        self.raw.Renderer_SwapBuffers = callback;
665    }
666
667    /// Set renderer swap buffers callback (typed). Unsafe due to FFI pointer cast.
668    #[cfg(feature = "multi-viewport")]
669    pub unsafe fn set_renderer_swap_buffers(
670        &mut self,
671        callback: Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
672    ) {
673        use trampolines::*;
674        *RENDERER_SWAP_BUFFERS_CB.lock().unwrap() = callback;
675        self.set_renderer_swap_buffers_raw(callback.map(|_| {
676            trampolines::renderer_swap_buffers
677                as unsafe extern "C" fn(*mut sys::ImGuiViewport, *mut c_void)
678        }));
679    }
680
681    /// Get access to the monitors vector
682    #[cfg(feature = "multi-viewport")]
683    pub fn monitors(&self) -> &crate::internal::ImVector<sys::ImGuiPlatformMonitor> {
684        unsafe {
685            crate::internal::imvector_cast_ref::<
686                sys::ImGuiPlatformMonitor,
687                sys::ImVector_ImGuiPlatformMonitor,
688            >(&self.raw.Monitors)
689        }
690    }
691
692    /// Get mutable access to the monitors vector
693    #[cfg(feature = "multi-viewport")]
694    pub fn monitors_mut(&mut self) -> &mut crate::internal::ImVector<sys::ImGuiPlatformMonitor> {
695        unsafe {
696            crate::internal::imvector_cast_mut::<
697                sys::ImGuiPlatformMonitor,
698                sys::ImVector_ImGuiPlatformMonitor,
699            >(&mut self.raw.Monitors)
700        }
701    }
702
703    /// Get access to the viewports vector
704    #[cfg(feature = "multi-viewport")]
705    pub fn viewports(&self) -> &crate::internal::ImVector<*mut sys::ImGuiViewport> {
706        unsafe {
707            crate::internal::imvector_cast_ref::<
708                *mut sys::ImGuiViewport,
709                sys::ImVector_ImGuiViewportPtr,
710            >(&self.raw.Viewports)
711        }
712    }
713
714    /// Get mutable access to the viewports vector
715    #[cfg(feature = "multi-viewport")]
716    pub fn viewports_mut(&mut self) -> &mut crate::internal::ImVector<*mut sys::ImGuiViewport> {
717        unsafe {
718            crate::internal::imvector_cast_mut::<
719                *mut sys::ImGuiViewport,
720                sys::ImVector_ImGuiViewportPtr,
721            >(&mut self.raw.Viewports)
722        }
723    }
724
725    /// Get an iterator over all viewports
726    #[cfg(feature = "multi-viewport")]
727    pub fn viewports_iter(&self) -> impl Iterator<Item = &Viewport> {
728        self.viewports()
729            .iter()
730            .map(|&ptr| unsafe { Viewport::from_raw(ptr) })
731    }
732
733    /// Get a mutable iterator over all viewports
734    #[cfg(feature = "multi-viewport")]
735    pub fn viewports_iter_mut(&mut self) -> impl Iterator<Item = &mut Viewport> {
736        self.viewports_mut()
737            .iter_mut()
738            .map(|&mut ptr| unsafe { Viewport::from_raw_mut(ptr) })
739    }
740
741    /// Get an iterator over all textures managed by the platform
742    ///
743    /// This is used by renderer backends during shutdown to destroy all textures.
744    pub fn textures(&self) -> crate::render::draw_data::TextureIterator<'_> {
745        unsafe {
746            let vector = &self.raw.Textures;
747            crate::render::draw_data::TextureIterator::new(
748                vector.Data,
749                vector.Data.add(vector.Size as usize),
750            )
751        }
752    }
753
754    /// Get the number of textures managed by the platform
755    pub fn textures_count(&self) -> usize {
756        self.raw.Textures.Size as usize
757    }
758
759    /// Get a specific texture by index
760    ///
761    /// Returns None if the index is out of bounds.
762    pub fn texture(&self, index: usize) -> Option<&crate::texture::TextureData> {
763        unsafe {
764            let vector = &self.raw.Textures;
765            if index >= vector.Size as usize {
766                return None;
767            }
768            let texture_ptr = *vector.Data.add(index);
769            if texture_ptr.is_null() {
770                return None;
771            }
772            Some(crate::texture::TextureData::from_raw(texture_ptr))
773        }
774    }
775
776    /// Get a mutable reference to a specific texture by index
777    ///
778    /// Returns None if the index is out of bounds.
779    pub fn texture_mut(&mut self, index: usize) -> Option<&mut crate::texture::TextureData> {
780        unsafe {
781            let vector = &self.raw.Textures;
782            if index >= vector.Size as usize {
783                return None;
784            }
785            let texture_ptr = *vector.Data.add(index);
786            if texture_ptr.is_null() {
787                return None;
788            }
789            Some(crate::texture::TextureData::from_raw(texture_ptr))
790        }
791    }
792
793    /// Set the renderer render state
794    ///
795    /// This is used by renderer backends to expose their current render state
796    /// to draw callbacks during rendering. The pointer should remain valid
797    /// during the entire render_draw_data() call.
798    ///
799    /// # Safety
800    ///
801    /// The caller must ensure that:
802    /// - The pointer is valid for the duration of the render call
803    /// - The pointed-to data matches the expected render state structure for the backend
804    /// - The pointer is set to null after rendering is complete
805    pub unsafe fn set_renderer_render_state(&mut self, render_state: *mut std::ffi::c_void) {
806        self.raw.Renderer_RenderState = render_state;
807    }
808
809    /// Get the current renderer render state
810    ///
811    /// Returns the render state pointer that was set by the renderer backend.
812    /// This is typically used by draw callbacks to access the current render state.
813    ///
814    /// # Safety
815    ///
816    /// The caller must ensure that:
817    /// - The returned pointer is cast to the correct render state type for the backend
818    /// - The pointer is only used during the render_draw_data() call
819    pub unsafe fn renderer_render_state(&self) -> *mut std::ffi::c_void {
820        self.raw.Renderer_RenderState
821    }
822}
823
824// TODO: Add safe wrappers for platform IO functionality:
825// - Viewport management
826// - Platform backend callbacks
827// - Renderer backend callbacks
828// - Monitor information
829// - Platform-specific settings
830
831/// Viewport structure for multi-viewport support
832///
833/// This is a transparent wrapper around `ImGuiViewport` that provides
834/// safe access to viewport functionality.
835#[repr(transparent)]
836pub struct Viewport {
837    raw: sys::ImGuiViewport,
838}
839
840impl Viewport {
841    /// Returns a reference to the main Dear ImGui viewport (safe wrapper)
842    ///
843    /// This is the same viewport used by `Ui::dockspace_over_main_viewport()`.
844    /// Requires an active ImGui context.
845    #[doc(alias = "GetMainViewport")]
846    pub fn main() -> &'static Self {
847        // SAFETY: With an active ImGui context, `igGetMainViewport()` returns
848        // a valid pointer to the global main viewport that lives for the
849        // duration of the context. We expose it as a shared reference.
850        unsafe { Self::from_raw(sys::igGetMainViewport() as *const sys::ImGuiViewport) }
851    }
852    /// Get a reference to the viewport from a raw pointer
853    ///
854    /// # Safety
855    ///
856    /// The caller must ensure that the pointer is valid and points to a valid
857    /// `ImGuiViewport` structure.
858    pub(crate) unsafe fn from_raw(raw: *const sys::ImGuiViewport) -> &'static Self {
859        unsafe { &*(raw as *const Self) }
860    }
861
862    /// Get a mutable reference to the viewport from a raw pointer
863    ///
864    /// # Safety
865    ///
866    /// The caller must ensure that the pointer is valid and points to a valid
867    /// `ImGuiViewport` structure, and that no other references exist.
868    pub unsafe fn from_raw_mut(raw: *mut sys::ImGuiViewport) -> &'static mut Self {
869        unsafe { &mut *(raw as *mut Self) }
870    }
871
872    /// Get the raw pointer to the underlying `ImGuiViewport`
873    pub fn as_raw(&self) -> *const sys::ImGuiViewport {
874        &self.raw as *const _
875    }
876
877    /// Get the raw mutable pointer to the underlying `ImGuiViewport`
878    pub fn as_raw_mut(&mut self) -> *mut sys::ImGuiViewport {
879        &mut self.raw as *mut _
880    }
881
882    /// Get the viewport ID
883    pub fn id(&self) -> sys::ImGuiID {
884        self.raw.ID
885    }
886
887    /// Set the viewport position
888    pub fn set_pos(&mut self, pos: [f32; 2]) {
889        self.raw.Pos.x = pos[0];
890        self.raw.Pos.y = pos[1];
891    }
892
893    /// Get the viewport position
894    pub fn pos(&self) -> [f32; 2] {
895        [self.raw.Pos.x, self.raw.Pos.y]
896    }
897
898    /// Set the viewport size
899    pub fn set_size(&mut self, size: [f32; 2]) {
900        self.raw.Size.x = size[0];
901        self.raw.Size.y = size[1];
902    }
903
904    /// Get the viewport size
905    pub fn size(&self) -> [f32; 2] {
906        [self.raw.Size.x, self.raw.Size.y]
907    }
908
909    /// Get the viewport work position (excluding menu bars, task bars, etc.)
910    pub fn work_pos(&self) -> [f32; 2] {
911        [self.raw.WorkPos.x, self.raw.WorkPos.y]
912    }
913
914    /// Get the viewport work size (excluding menu bars, task bars, etc.)
915    pub fn work_size(&self) -> [f32; 2] {
916        [self.raw.WorkSize.x, self.raw.WorkSize.y]
917    }
918
919    /// Check if this is the main viewport
920    ///
921    /// Note: Main viewport is typically identified by ID == 0 or by checking if it's not a platform window
922    #[cfg(feature = "multi-viewport")]
923    pub fn is_main(&self) -> bool {
924        self.raw.ID == 0
925            || (self.raw.Flags & (crate::ViewportFlags::IS_PLATFORM_WINDOW.bits())) == 0
926    }
927
928    #[cfg(not(feature = "multi-viewport"))]
929    pub fn is_main(&self) -> bool {
930        self.raw.ID == 0
931    }
932
933    /// Check if this is a platform window (not the main viewport)
934    #[cfg(feature = "multi-viewport")]
935    pub fn is_platform_window(&self) -> bool {
936        (self.raw.Flags & (crate::ViewportFlags::IS_PLATFORM_WINDOW.bits())) != 0
937    }
938
939    #[cfg(not(feature = "multi-viewport"))]
940    pub fn is_platform_window(&self) -> bool {
941        false
942    }
943
944    /// Check if this is a platform monitor
945    #[cfg(feature = "multi-viewport")]
946    pub fn is_platform_monitor(&self) -> bool {
947        (self.raw.Flags & (crate::ViewportFlags::IS_PLATFORM_MONITOR.bits())) != 0
948    }
949
950    #[cfg(not(feature = "multi-viewport"))]
951    pub fn is_platform_monitor(&self) -> bool {
952        false
953    }
954
955    /// Check if this viewport is owned by the application
956    #[cfg(feature = "multi-viewport")]
957    pub fn is_owned_by_app(&self) -> bool {
958        (self.raw.Flags & (crate::ViewportFlags::OWNED_BY_APP.bits())) != 0
959    }
960
961    #[cfg(not(feature = "multi-viewport"))]
962    pub fn is_owned_by_app(&self) -> bool {
963        false
964    }
965
966    /// Get the platform user data
967    pub fn platform_user_data(&self) -> *mut c_void {
968        self.raw.PlatformUserData
969    }
970
971    /// Set the platform user data
972    pub fn set_platform_user_data(&mut self, data: *mut c_void) {
973        self.raw.PlatformUserData = data;
974    }
975
976    /// Get the renderer user data
977    pub fn renderer_user_data(&self) -> *mut c_void {
978        self.raw.RendererUserData
979    }
980
981    /// Set the renderer user data
982    pub fn set_renderer_user_data(&mut self, data: *mut c_void) {
983        self.raw.RendererUserData = data;
984    }
985
986    /// Get the platform handle
987    pub fn platform_handle(&self) -> *mut c_void {
988        self.raw.PlatformHandle
989    }
990
991    /// Set the platform handle
992    pub fn set_platform_handle(&mut self, handle: *mut c_void) {
993        self.raw.PlatformHandle = handle;
994    }
995
996    /// Check if the platform window was created
997    pub fn platform_window_created(&self) -> bool {
998        self.raw.PlatformWindowCreated
999    }
1000
1001    /// Set whether the platform window was created
1002    pub fn set_platform_window_created(&mut self, created: bool) {
1003        self.raw.PlatformWindowCreated = created;
1004    }
1005
1006    /// Check if the platform requested move
1007    pub fn platform_request_move(&self) -> bool {
1008        self.raw.PlatformRequestMove
1009    }
1010
1011    /// Set whether the platform requested move
1012    pub fn set_platform_request_move(&mut self, request: bool) {
1013        self.raw.PlatformRequestMove = request;
1014    }
1015
1016    /// Check if the platform requested resize
1017    pub fn platform_request_resize(&self) -> bool {
1018        self.raw.PlatformRequestResize
1019    }
1020
1021    /// Set whether the platform requested resize
1022    pub fn set_platform_request_resize(&mut self, request: bool) {
1023        self.raw.PlatformRequestResize = request;
1024    }
1025
1026    /// Check if the platform requested close
1027    pub fn platform_request_close(&self) -> bool {
1028        self.raw.PlatformRequestClose
1029    }
1030
1031    /// Set whether the platform requested close
1032    pub fn set_platform_request_close(&mut self, request: bool) {
1033        self.raw.PlatformRequestClose = request;
1034    }
1035
1036    /// Get the viewport flags
1037    pub fn flags(&self) -> sys::ImGuiViewportFlags {
1038        self.raw.Flags
1039    }
1040
1041    /// Set the viewport flags
1042    pub fn set_flags(&mut self, flags: sys::ImGuiViewportFlags) {
1043        self.raw.Flags = flags;
1044    }
1045
1046    /// Get the DPI scale factor
1047    #[cfg(feature = "multi-viewport")]
1048    pub fn dpi_scale(&self) -> f32 {
1049        self.raw.DpiScale
1050    }
1051
1052    /// Set the DPI scale factor
1053    #[cfg(feature = "multi-viewport")]
1054    pub fn set_dpi_scale(&mut self, scale: f32) {
1055        self.raw.DpiScale = scale;
1056    }
1057
1058    /// Get the parent viewport ID
1059    #[cfg(feature = "multi-viewport")]
1060    pub fn parent_viewport_id(&self) -> sys::ImGuiID {
1061        self.raw.ParentViewportId
1062    }
1063
1064    /// Set the parent viewport ID
1065    #[cfg(feature = "multi-viewport")]
1066    pub fn set_parent_viewport_id(&mut self, id: sys::ImGuiID) {
1067        self.raw.ParentViewportId = id;
1068    }
1069
1070    /// Get the draw data pointer
1071    #[cfg(feature = "multi-viewport")]
1072    pub fn draw_data(&self) -> *mut sys::ImDrawData {
1073        self.raw.DrawData
1074    }
1075
1076    /// Get the draw data as a reference (if available)
1077    #[cfg(feature = "multi-viewport")]
1078    pub fn draw_data_ref(&self) -> Option<&sys::ImDrawData> {
1079        if self.raw.DrawData.is_null() {
1080            None
1081        } else {
1082            Some(unsafe { &*self.raw.DrawData })
1083        }
1084    }
1085
1086    /// Get the framebuffer scale
1087    #[cfg(feature = "multi-viewport")]
1088    pub fn framebuffer_scale(&self) -> [f32; 2] {
1089        [self.raw.FramebufferScale.x, self.raw.FramebufferScale.y]
1090    }
1091
1092    /// Set the framebuffer scale
1093    #[cfg(feature = "multi-viewport")]
1094    pub fn set_framebuffer_scale(&mut self, scale: [f32; 2]) {
1095        self.raw.FramebufferScale.x = scale[0];
1096        self.raw.FramebufferScale.y = scale[1];
1097    }
1098}
1099
1100// TODO: Add more viewport functionality:
1101// - Platform window handle access
1102// - Renderer data access
1103// - DPI scale information
1104// - Monitor information