1use parking_lot::ReentrantMutex;
9use std::cell::UnsafeCell;
10use std::ffi::CString;
11use std::ops::Drop;
12use std::path::PathBuf;
13use std::ptr;
14use std::rc::{Rc, Weak};
15
16use crate::clipboard::{ClipboardBackend, ClipboardContext};
17use crate::fonts::{Font, FontAtlas, SharedFontAtlas};
18use crate::io::Io;
19
20use crate::sys;
21
22#[derive(Debug)]
48pub struct Context {
49 raw: *mut sys::ImGuiContext,
50 alive: Rc<()>,
51 shared_font_atlas: Option<SharedFontAtlas>,
52 ini_filename: Option<CString>,
53 log_filename: Option<CString>,
54 platform_name: Option<CString>,
55 renderer_name: Option<CString>,
56 clipboard_ctx: Box<UnsafeCell<ClipboardContext>>,
61 ui: crate::ui::Ui,
62}
63
64static CTX_MUTEX: ReentrantMutex<()> = parking_lot::const_reentrant_mutex(());
67
68fn clear_current_context() {
69 unsafe {
70 sys::igSetCurrentContext(ptr::null_mut());
71 }
72}
73
74fn no_current_context() -> bool {
75 let ctx = unsafe { sys::igGetCurrentContext() };
76 ctx.is_null()
77}
78
79impl Context {
80 pub fn try_create() -> crate::error::ImGuiResult<Context> {
84 Self::try_create_internal(None)
85 }
86
87 pub fn try_create_with_shared_font_atlas(
89 shared_font_atlas: SharedFontAtlas,
90 ) -> crate::error::ImGuiResult<Context> {
91 Self::try_create_internal(Some(shared_font_atlas))
92 }
93
94 pub fn create() -> Context {
98 Self::try_create().expect("Failed to create Dear ImGui context")
99 }
100
101 pub fn create_with_shared_font_atlas(shared_font_atlas: SharedFontAtlas) -> Context {
103 Self::try_create_with_shared_font_atlas(shared_font_atlas)
104 .expect("Failed to create Dear ImGui context")
105 }
106
107 pub fn as_raw(&self) -> *mut sys::ImGuiContext {
109 self.raw
110 }
111
112 pub fn alive_token(&self) -> ContextAliveToken {
117 ContextAliveToken(Rc::downgrade(&self.alive))
118 }
119
120 fn try_create_internal(
123 mut shared_font_atlas: Option<SharedFontAtlas>,
124 ) -> crate::error::ImGuiResult<Context> {
125 let _guard = CTX_MUTEX.lock();
126
127 if !no_current_context() {
128 return Err(crate::error::ImGuiError::ContextAlreadyActive);
129 }
130
131 let shared_font_atlas_ptr = match &mut shared_font_atlas {
132 Some(atlas) => atlas.as_ptr_mut(),
133 None => ptr::null_mut(),
134 };
135
136 let raw = unsafe { sys::igCreateContext(shared_font_atlas_ptr) };
138 if raw.is_null() {
139 return Err(crate::error::ImGuiError::ContextCreation {
140 reason: "ImGui_CreateContext returned null".to_string(),
141 });
142 }
143
144 unsafe {
146 sys::igSetCurrentContext(raw);
147 }
148
149 Ok(Context {
150 raw,
151 alive: Rc::new(()),
152 shared_font_atlas,
153 ini_filename: None,
154 log_filename: None,
155 platform_name: None,
156 renderer_name: None,
157 clipboard_ctx: Box::new(UnsafeCell::new(ClipboardContext::dummy())),
158 ui: crate::ui::Ui::new(),
159 })
160 }
161
162 pub fn io_mut(&mut self) -> &mut Io {
164 let _guard = CTX_MUTEX.lock();
165 unsafe {
166 let io_ptr = sys::igGetIO_Nil();
168 if io_ptr.is_null() {
169 panic!("Context::io_mut() requires an active ImGui context");
170 }
171 &mut *(io_ptr as *mut Io)
172 }
173 }
174
175 pub fn io(&self) -> &crate::io::Io {
177 let _guard = CTX_MUTEX.lock();
178 unsafe {
179 let io_ptr = sys::igGetIO_Nil();
181 if io_ptr.is_null() {
182 panic!("Context::io() requires an active ImGui context");
183 }
184 &*(io_ptr as *const crate::io::Io)
185 }
186 }
187
188 pub fn style(&self) -> &crate::style::Style {
190 let _guard = CTX_MUTEX.lock();
191 unsafe {
192 let style_ptr = sys::igGetStyle();
193 if style_ptr.is_null() {
194 panic!("Context::style() requires an active ImGui context");
195 }
196 &*(style_ptr as *const crate::style::Style)
197 }
198 }
199
200 pub fn style_mut(&mut self) -> &mut crate::style::Style {
202 let _guard = CTX_MUTEX.lock();
203 unsafe {
204 let style_ptr = sys::igGetStyle();
205 if style_ptr.is_null() {
206 panic!("Context::style_mut() requires an active ImGui context");
207 }
208 &mut *(style_ptr as *mut crate::style::Style)
209 }
210 }
211
212 pub fn frame(&mut self) -> &mut crate::ui::Ui {
217 let _guard = CTX_MUTEX.lock();
218
219 unsafe {
220 let io = sys::igGetIO_Nil();
225 if !io.is_null() && ((*io).DisplaySize.x < 0.0 || (*io).DisplaySize.y < 0.0) {
226 panic!(
227 "Context::frame() called with invalid io.DisplaySize ({}, {}). \
228Set io.DisplaySize (and typically io.DeltaTime) before starting a frame. \
229If you are using a windowing/event-loop library, prefer a platform backend such as \
230dear-imgui-winit::WinitPlatform::prepare_frame().",
231 (*io).DisplaySize.x,
232 (*io).DisplaySize.y
233 );
234 }
235 sys::igNewFrame();
236 }
237 &mut self.ui
238 }
239
240 pub fn frame_with<F, R>(&mut self, f: F) -> R
242 where
243 F: FnOnce(&crate::ui::Ui) -> R,
244 {
245 let ui = self.frame();
246 f(ui)
247 }
248
249 pub fn render(&mut self) -> &crate::render::DrawData {
254 let _guard = CTX_MUTEX.lock();
255 unsafe {
256 sys::igRender();
257 let dd = sys::igGetDrawData();
258 if dd.is_null() {
259 panic!("Context::render() returned null draw data");
260 }
261 &*(dd as *const crate::render::DrawData)
262 }
263 }
264
265 pub fn draw_data(&self) -> Option<&crate::render::DrawData> {
270 let _guard = CTX_MUTEX.lock();
271 unsafe {
272 let draw_data = sys::igGetDrawData();
273 if draw_data.is_null() {
274 None
275 } else {
276 let data = &*(draw_data as *const crate::render::DrawData);
277 if data.valid() { Some(data) } else { None }
278 }
279 }
280 }
281
282 pub fn register_user_texture(&mut self, texture: &mut crate::texture::TextureData) {
296 let _guard = CTX_MUTEX.lock();
297 assert!(
298 self.is_current_context(),
299 "Context::register_user_texture() requires the context to be current"
300 );
301 unsafe {
302 sys::igRegisterUserTexture(texture.as_raw_mut());
303 }
304 }
305
306 pub fn register_user_texture_token(
314 &mut self,
315 texture: &mut crate::texture::TextureData,
316 ) -> RegisteredUserTexture {
317 self.register_user_texture(texture);
318 RegisteredUserTexture {
319 ctx: self.raw,
320 tex: texture.as_raw_mut(),
321 }
322 }
323
324 pub fn unregister_user_texture(&mut self, texture: &mut crate::texture::TextureData) {
328 let _guard = CTX_MUTEX.lock();
329 assert!(
330 self.is_current_context(),
331 "Context::unregister_user_texture() requires the context to be current"
332 );
333 unsafe {
334 sys::igUnregisterUserTexture(texture.as_raw_mut());
335 }
336 }
337
338 pub fn set_ini_filename<P: Into<PathBuf>>(
344 &mut self,
345 filename: Option<P>,
346 ) -> crate::error::ImGuiResult<()> {
347 use crate::error::SafeStringConversion;
348 let _guard = CTX_MUTEX.lock();
349
350 self.ini_filename = match filename {
351 Some(f) => Some(f.into().to_string_lossy().to_cstring_safe()?),
352 None => None,
353 };
354
355 unsafe {
356 let io = sys::igGetIO_Nil();
357 let ptr = self
358 .ini_filename
359 .as_ref()
360 .map(|s| s.as_ptr())
361 .unwrap_or(ptr::null());
362 (*io).IniFilename = ptr;
363 }
364 Ok(())
365 }
366
367 pub fn set_log_filename<P: Into<PathBuf>>(
375 &mut self,
376 filename: Option<P>,
377 ) -> crate::error::ImGuiResult<()> {
378 use crate::error::SafeStringConversion;
379 let _guard = CTX_MUTEX.lock();
380
381 self.log_filename = match filename {
382 Some(f) => Some(f.into().to_string_lossy().to_cstring_safe()?),
383 None => None,
384 };
385
386 unsafe {
387 let io = sys::igGetIO_Nil();
388 let ptr = self
389 .log_filename
390 .as_ref()
391 .map(|s| s.as_ptr())
392 .unwrap_or(ptr::null());
393 (*io).LogFilename = ptr;
394 }
395 Ok(())
396 }
397
398 pub fn set_platform_name<S: Into<String>>(
406 &mut self,
407 name: Option<S>,
408 ) -> crate::error::ImGuiResult<()> {
409 use crate::error::SafeStringConversion;
410 let _guard = CTX_MUTEX.lock();
411
412 self.platform_name = match name {
413 Some(n) => Some(n.into().to_cstring_safe()?),
414 None => None,
415 };
416
417 unsafe {
418 let io = sys::igGetIO_Nil();
419 let ptr = self
420 .platform_name
421 .as_ref()
422 .map(|s| s.as_ptr())
423 .unwrap_or(ptr::null());
424 (*io).BackendPlatformName = ptr;
425 }
426 Ok(())
427 }
428
429 pub fn set_renderer_name<S: Into<String>>(
437 &mut self,
438 name: Option<S>,
439 ) -> crate::error::ImGuiResult<()> {
440 use crate::error::SafeStringConversion;
441 let _guard = CTX_MUTEX.lock();
442
443 self.renderer_name = match name {
444 Some(n) => Some(n.into().to_cstring_safe()?),
445 None => None,
446 };
447
448 unsafe {
449 let io = sys::igGetIO_Nil();
450 if io.is_null() {
451 panic!("igGetIO_Nil() returned null");
452 }
453 let ptr = self
454 .renderer_name
455 .as_ref()
456 .map(|s| s.as_ptr())
457 .unwrap_or(ptr::null());
458 (*io).BackendRendererName = ptr;
459 }
460 Ok(())
461 }
462
463 pub fn platform_io(&self) -> &crate::platform_io::PlatformIo {
470 let _guard = CTX_MUTEX.lock();
471 unsafe {
472 let pio = sys::igGetPlatformIO_Nil();
473 if pio.is_null() {
474 panic!("Context::platform_io() requires an active ImGui context");
475 }
476 crate::platform_io::PlatformIo::from_raw(pio)
477 }
478 }
479
480 pub fn platform_io_mut(&mut self) -> &mut crate::platform_io::PlatformIo {
485 let _guard = CTX_MUTEX.lock();
486 unsafe {
487 let pio = sys::igGetPlatformIO_Nil();
488 if pio.is_null() {
489 panic!("igGetPlatformIO_Nil() returned null");
490 }
491 crate::platform_io::PlatformIo::from_raw_mut(pio)
492 }
493 }
494
495 #[doc(alias = "GetMainViewport")]
500 pub fn main_viewport(&mut self) -> &crate::platform_io::Viewport {
501 let _guard = CTX_MUTEX.lock();
502 unsafe {
503 let ptr = sys::igGetMainViewport();
504 if ptr.is_null() {
505 panic!("Context::main_viewport() requires an active ImGui context");
506 }
507 crate::platform_io::Viewport::from_raw(ptr as *const sys::ImGuiViewport)
508 }
509 }
510
511 #[cfg(feature = "multi-viewport")]
513 pub fn enable_multi_viewport(&mut self) {
514 crate::viewport_backend::utils::enable_viewport_flags(self.io_mut());
516 }
517
518 #[cfg(feature = "multi-viewport")]
523 pub fn update_platform_windows(&mut self) {
524 let _guard = CTX_MUTEX.lock();
525 unsafe {
526 let main_viewport = sys::igGetMainViewport();
528 if !main_viewport.is_null() && (*main_viewport).PlatformHandle.is_null() {
529 eprintln!("update_platform_windows: main viewport not set up, setting it up now");
530 }
533
534 sys::igUpdatePlatformWindows();
535 }
536 }
537
538 #[cfg(feature = "multi-viewport")]
543 pub fn render_platform_windows_default(&mut self) {
544 let _guard = CTX_MUTEX.lock();
545 unsafe {
546 sys::igRenderPlatformWindowsDefault(std::ptr::null_mut(), std::ptr::null_mut());
547 }
548 }
549
550 #[cfg(feature = "multi-viewport")]
555 pub fn destroy_platform_windows(&mut self) {
556 let _guard = CTX_MUTEX.lock();
557 unsafe {
558 sys::igDestroyPlatformWindows();
559 }
560 }
561
562 pub fn suspend(self) -> SuspendedContext {
564 let _guard = CTX_MUTEX.lock();
565 assert!(
566 self.is_current_context(),
567 "context to be suspended is not the active context"
568 );
569 clear_current_context();
570 SuspendedContext(self)
571 }
572
573 fn is_current_context(&self) -> bool {
574 let ctx = unsafe { sys::igGetCurrentContext() };
575 self.raw == ctx
576 }
577
578 pub fn push_font(&mut self, font: &Font) {
580 let _guard = CTX_MUTEX.lock();
581 unsafe {
582 sys::igPushFont(font.raw(), 0.0);
583 }
584 }
585
586 #[doc(alias = "PopFont")]
590 pub fn pop_font(&mut self) {
591 let _guard = CTX_MUTEX.lock();
592 unsafe {
593 sys::igPopFont();
594 }
595 }
596
597 #[doc(alias = "GetFont")]
599 pub fn current_font(&self) -> &Font {
600 let _guard = CTX_MUTEX.lock();
601 unsafe { Font::from_raw(sys::igGetFont() as *const _) }
602 }
603
604 #[doc(alias = "GetFontSize")]
606 pub fn current_font_size(&self) -> f32 {
607 let _guard = CTX_MUTEX.lock();
608 unsafe { sys::igGetFontSize() }
609 }
610
611 pub fn font_atlas(&self) -> FontAtlas {
613 let _guard = CTX_MUTEX.lock();
614
615 #[cfg(all(target_arch = "wasm32", feature = "wasm-font-atlas-experimental"))]
620 unsafe {
621 let io = sys::igGetIO_Nil();
622 let atlas_ptr = (*io).Fonts;
623 assert!(
624 !atlas_ptr.is_null(),
625 "ImGui IO Fonts pointer is null on wasm; provider not initialized?"
626 );
627 FontAtlas::from_raw(atlas_ptr)
628 }
629
630 #[cfg(all(target_arch = "wasm32", not(feature = "wasm-font-atlas-experimental")))]
632 {
633 panic!(
634 "font_atlas() is not supported on wasm32 targets without \
635 `wasm-font-atlas-experimental` feature; \
636 see docs/WASM.md for current limitations."
637 );
638 }
639
640 #[cfg(not(target_arch = "wasm32"))]
641 unsafe {
642 let io = sys::igGetIO_Nil();
643 let atlas_ptr = (*io).Fonts;
644 FontAtlas::from_raw(atlas_ptr)
645 }
646 }
647
648 pub fn font_atlas_mut(&mut self) -> FontAtlas {
650 let _guard = CTX_MUTEX.lock();
651
652 #[cfg(all(target_arch = "wasm32", feature = "wasm-font-atlas-experimental"))]
657 unsafe {
658 let io = sys::igGetIO_Nil();
659 let atlas_ptr = (*io).Fonts;
660 assert!(
661 !atlas_ptr.is_null(),
662 "ImGui IO Fonts pointer is null on wasm; provider not initialized?"
663 );
664 return FontAtlas::from_raw(atlas_ptr);
665 }
666
667 #[cfg(all(target_arch = "wasm32", not(feature = "wasm-font-atlas-experimental")))]
669 {
670 panic!(
671 "font_atlas_mut()/fonts() are not supported on wasm32 targets yet; \
672 enable `wasm-font-atlas-experimental` to opt-in for experiments."
673 );
674 }
675
676 #[cfg(not(target_arch = "wasm32"))]
677 unsafe {
678 let io = sys::igGetIO_Nil();
679 let atlas_ptr = (*io).Fonts;
680 FontAtlas::from_raw(atlas_ptr)
681 }
682 }
683
684 pub fn fonts(&mut self) -> FontAtlas {
688 self.font_atlas_mut()
689 }
690
691 pub fn clone_shared_font_atlas(&mut self) -> Option<SharedFontAtlas> {
693 self.shared_font_atlas.clone()
694 }
695
696 #[doc(alias = "LoadIniSettingsFromMemory")]
698 pub fn load_ini_settings(&mut self, data: &str) {
699 let _guard = CTX_MUTEX.lock();
700 unsafe {
701 sys::igLoadIniSettingsFromMemory(data.as_ptr() as *const _, data.len());
702 }
703 }
704
705 #[doc(alias = "SaveIniSettingsToMemory")]
707 pub fn save_ini_settings(&mut self, buf: &mut String) {
708 let _guard = CTX_MUTEX.lock();
709 unsafe {
710 let mut out_ini_size: usize = 0;
711 let data_ptr = sys::igSaveIniSettingsToMemory(&mut out_ini_size as *mut usize);
712 if data_ptr.is_null() || out_ini_size == 0 {
713 return;
714 }
715
716 let mut bytes = std::slice::from_raw_parts(data_ptr as *const u8, out_ini_size);
717 if bytes.last() == Some(&0) {
718 bytes = &bytes[..bytes.len().saturating_sub(1)];
719 }
720 buf.push_str(&String::from_utf8_lossy(bytes));
721 }
722 }
723
724 #[cfg(not(target_arch = "wasm32"))]
730 #[doc(alias = "LoadIniSettingsFromDisk")]
731 pub fn load_ini_settings_from_disk<P: Into<PathBuf>>(
732 &mut self,
733 filename: P,
734 ) -> crate::error::ImGuiResult<()> {
735 use crate::error::SafeStringConversion;
736 let _guard = CTX_MUTEX.lock();
737 let cstr = filename.into().to_string_lossy().to_cstring_safe()?;
738 unsafe { sys::igLoadIniSettingsFromDisk(cstr.as_ptr()) }
739 Ok(())
740 }
741
742 #[cfg(not(target_arch = "wasm32"))]
748 #[doc(alias = "SaveIniSettingsToDisk")]
749 pub fn save_ini_settings_to_disk<P: Into<PathBuf>>(
750 &mut self,
751 filename: P,
752 ) -> crate::error::ImGuiResult<()> {
753 use crate::error::SafeStringConversion;
754 let _guard = CTX_MUTEX.lock();
755 let cstr = filename.into().to_string_lossy().to_cstring_safe()?;
756 unsafe { sys::igSaveIniSettingsToDisk(cstr.as_ptr()) }
757 Ok(())
758 }
759
760 #[doc(alias = "GetClipboardText")]
767 pub fn clipboard_text(&self) -> Option<String> {
768 let _guard = CTX_MUTEX.lock();
769 unsafe {
770 let ptr = sys::igGetClipboardText();
771 if ptr.is_null() {
772 return None;
773 }
774 Some(std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned())
775 }
776 }
777
778 #[doc(alias = "SetClipboardText")]
785 pub fn set_clipboard_text(&self, text: impl AsRef<str>) {
786 let _guard = CTX_MUTEX.lock();
787 unsafe {
788 sys::igSetClipboardText(self.ui.scratch_txt(text.as_ref()));
789 }
790 }
791
792 pub fn set_clipboard_backend<T: ClipboardBackend>(&mut self, backend: T) {
794 let _guard = CTX_MUTEX.lock();
795
796 let clipboard_ctx: Box<UnsafeCell<_>> =
797 Box::new(UnsafeCell::new(ClipboardContext::new(backend)));
798
799 #[cfg(not(target_arch = "wasm32"))]
808 unsafe {
809 let platform_io = sys::igGetPlatformIO_Nil();
810 if platform_io.is_null() {
811 panic!("Context::set_clipboard_backend() requires an active ImGui context");
812 }
813 (*platform_io).Platform_SetClipboardTextFn = Some(crate::clipboard::set_clipboard_text);
814 (*platform_io).Platform_GetClipboardTextFn = Some(crate::clipboard::get_clipboard_text);
815 (*platform_io).Platform_ClipboardUserData = clipboard_ctx.get() as *mut _;
816 }
817
818 self.clipboard_ctx = clipboard_ctx;
819 }
820}
821
822impl Drop for Context {
823 fn drop(&mut self) {
824 let _guard = CTX_MUTEX.lock();
825 unsafe {
826 if !self.raw.is_null() {
827 if sys::igGetCurrentContext() == self.raw {
828 clear_current_context();
829 }
830 sys::igDestroyContext(self.raw);
831 }
832 }
833 }
834}
835
836#[cfg(test)]
837mod tests {
838 use super::Context;
839
840 #[test]
841 fn platform_io_shared_and_mut_views_match() {
842 let mut ctx = Context::create();
843 let shared = ctx.platform_io().as_raw();
844 let mutable = ctx.platform_io_mut().as_raw();
845 assert_eq!(shared, mutable);
846 }
847
848 #[cfg(feature = "multi-viewport")]
849 #[test]
850 fn platform_io_get_window_pos_and_size_setters_install_handlers() {
851 unsafe extern "C" fn get_pos(
852 _viewport: *mut crate::sys::ImGuiViewport,
853 ) -> crate::sys::ImVec2 {
854 crate::sys::ImVec2 { x: 10.0, y: 20.0 }
855 }
856 unsafe extern "C" fn get_size(
857 _viewport: *mut crate::sys::ImGuiViewport,
858 ) -> crate::sys::ImVec2 {
859 crate::sys::ImVec2 { x: 30.0, y: 40.0 }
860 }
861
862 let mut ctx = Context::create();
863 let pio = ctx.platform_io_mut();
864
865 pio.set_platform_get_window_pos_raw(Some(get_pos));
866 pio.set_platform_get_window_size_raw(Some(get_size));
867
868 let raw = unsafe { &*pio.as_raw() };
869 assert!(raw.Platform_GetWindowPos.is_some());
870 assert!(raw.Platform_GetWindowSize.is_some());
871
872 pio.set_platform_get_window_pos_raw(None);
873 pio.set_platform_get_window_size_raw(None);
874
875 let raw = unsafe { &*pio.as_raw() };
876 assert!(raw.Platform_GetWindowPos.is_none());
877 assert!(raw.Platform_GetWindowSize.is_none());
878 }
879}
880
881#[derive(Debug)]
885pub struct SuspendedContext(Context);
886
887#[derive(Clone, Debug)]
889pub struct ContextAliveToken(Weak<()>);
890
891impl ContextAliveToken {
892 pub fn is_alive(&self) -> bool {
894 self.0.upgrade().is_some()
895 }
896}
897
898impl SuspendedContext {
899 pub fn try_create() -> crate::error::ImGuiResult<Self> {
901 Self::try_create_internal(None)
902 }
903
904 pub fn try_create_with_shared_font_atlas(
906 shared_font_atlas: SharedFontAtlas,
907 ) -> crate::error::ImGuiResult<Self> {
908 Self::try_create_internal(Some(shared_font_atlas))
909 }
910
911 pub fn create() -> Self {
913 Self::try_create().expect("Failed to create Dear ImGui context")
914 }
915
916 pub fn create_with_shared_font_atlas(shared_font_atlas: SharedFontAtlas) -> Self {
918 Self::try_create_with_shared_font_atlas(shared_font_atlas)
919 .expect("Failed to create Dear ImGui context")
920 }
921
922 fn try_create_internal(
925 mut shared_font_atlas: Option<SharedFontAtlas>,
926 ) -> crate::error::ImGuiResult<Self> {
927 let _guard = CTX_MUTEX.lock();
928
929 let shared_font_atlas_ptr = match &mut shared_font_atlas {
930 Some(atlas) => atlas.as_ptr_mut(),
931 None => ptr::null_mut(),
932 };
933
934 let raw = unsafe { sys::igCreateContext(shared_font_atlas_ptr) };
935 if raw.is_null() {
936 return Err(crate::error::ImGuiError::ContextCreation {
937 reason: "ImGui_CreateContext returned null".to_string(),
938 });
939 }
940
941 let ctx = Context {
942 raw,
943 alive: Rc::new(()),
944 shared_font_atlas,
945 ini_filename: None,
946 log_filename: None,
947 platform_name: None,
948 renderer_name: None,
949 clipboard_ctx: Box::new(UnsafeCell::new(ClipboardContext::dummy())),
950 ui: crate::ui::Ui::new(),
951 };
952
953 if ctx.is_current_context() {
955 clear_current_context();
956 }
957
958 Ok(SuspendedContext(ctx))
959 }
960
961 pub fn activate(self) -> Result<Context, SuspendedContext> {
966 let _guard = CTX_MUTEX.lock();
967 if no_current_context() {
968 unsafe {
969 sys::igSetCurrentContext(self.0.raw);
970 }
971 Ok(self.0)
972 } else {
973 Err(self)
974 }
975 }
976}
977
978#[derive(Debug)]
987pub struct RegisteredUserTexture {
988 ctx: *mut sys::ImGuiContext,
989 tex: *mut sys::ImTextureData,
990}
991
992impl Drop for RegisteredUserTexture {
993 fn drop(&mut self) {
994 if self.ctx.is_null() || self.tex.is_null() {
995 return;
996 }
997
998 let _guard = CTX_MUTEX.lock();
999 unsafe {
1000 let prev = sys::igGetCurrentContext();
1003 if prev != self.ctx {
1004 sys::igSetCurrentContext(self.ctx);
1005 }
1006 sys::igUnregisterUserTexture(self.tex);
1007 if prev != self.ctx {
1008 sys::igSetCurrentContext(prev);
1009 }
1010 }
1011 }
1012}
1013
1014