dear_imgui_rs/context/
core.rs1use std::ffi::CString;
2use std::ptr;
3use std::rc::{Rc, Weak};
4
5use crate::clipboard::ClipboardContext;
6use crate::fonts::SharedFontAtlas;
7use crate::io::Io;
8use crate::sys;
9
10use super::binding::{CTX_MUTEX, clear_current_context, no_current_context, with_bound_context};
11use super::texture_registry::unregister_user_textures_for_context;
12
13#[derive(Debug)]
39pub struct Context {
40 pub(super) raw: *mut sys::ImGuiContext,
41 pub(super) alive: Rc<()>,
42 pub(in crate::context) shared_font_atlas: Option<SharedFontAtlas>,
43 pub(in crate::context) ini_filename: Option<CString>,
44 pub(in crate::context) log_filename: Option<CString>,
45 pub(in crate::context) platform_name: Option<CString>,
46 pub(in crate::context) renderer_name: Option<CString>,
47 pub(in crate::context) clipboard_ctx: Box<ClipboardContext>,
50 pub(in crate::context) ui: crate::ui::Ui,
51}
52
53#[derive(Clone, Debug)]
55pub struct ContextAliveToken(Weak<()>);
56
57impl ContextAliveToken {
58 pub(in crate::context) fn new(alive: &Rc<()>) -> Self {
59 Self(Rc::downgrade(alive))
60 }
61
62 pub fn is_alive(&self) -> bool {
64 self.0.upgrade().is_some()
65 }
66}
67
68impl Context {
69 pub fn try_create() -> crate::error::ImGuiResult<Context> {
73 Self::try_create_internal(None)
74 }
75
76 pub fn try_create_with_shared_font_atlas(
78 shared_font_atlas: SharedFontAtlas,
79 ) -> crate::error::ImGuiResult<Context> {
80 Self::try_create_internal(Some(shared_font_atlas))
81 }
82
83 pub fn create() -> Context {
87 Self::try_create().expect("Failed to create Dear ImGui context")
88 }
89
90 pub fn create_with_shared_font_atlas(shared_font_atlas: SharedFontAtlas) -> Context {
92 Self::try_create_with_shared_font_atlas(shared_font_atlas)
93 .expect("Failed to create Dear ImGui context")
94 }
95
96 pub fn as_raw(&self) -> *mut sys::ImGuiContext {
98 self.raw
99 }
100
101 pub fn alive_token(&self) -> ContextAliveToken {
106 ContextAliveToken::new(&self.alive)
107 }
108
109 pub(super) fn io_ptr(&self, caller: &str) -> *mut sys::ImGuiIO {
112 let io = unsafe { sys::igGetIO_ContextPtr(self.raw) };
113 if io.is_null() {
114 panic!("{caller} requires a valid ImGui context");
115 }
116 io
117 }
118
119 pub(super) fn platform_io_ptr(&self, caller: &str) -> *mut sys::ImGuiPlatformIO {
120 let pio = unsafe { sys::igGetPlatformIO_ContextPtr(self.raw) };
121 if pio.is_null() {
122 panic!("{caller} requires a valid ImGui context");
123 }
124 pio
125 }
126
127 pub(super) fn assert_current_context(&self, caller: &str) {
128 assert!(
129 self.is_current_context(),
130 "{caller} requires this context to be current"
131 );
132 }
133
134 fn try_create_internal(
135 mut shared_font_atlas: Option<SharedFontAtlas>,
136 ) -> crate::error::ImGuiResult<Context> {
137 let _guard = CTX_MUTEX.lock();
138
139 if !no_current_context() {
140 return Err(crate::error::ImGuiError::ContextAlreadyActive);
141 }
142
143 let shared_font_atlas_ptr = match &mut shared_font_atlas {
144 Some(atlas) => atlas.as_ptr_mut(),
145 None => ptr::null_mut(),
146 };
147
148 let raw = unsafe { sys::igCreateContext(shared_font_atlas_ptr) };
150 if raw.is_null() {
151 return Err(crate::error::ImGuiError::ContextCreation {
152 reason: "ImGui_CreateContext returned null".to_string(),
153 });
154 }
155
156 unsafe {
158 sys::igSetCurrentContext(raw);
159 }
160
161 let alive = Rc::new(());
162 let ui = crate::ui::Ui::new(raw, ContextAliveToken::new(&alive));
163
164 Ok(Context {
165 raw,
166 alive,
167 shared_font_atlas,
168 ini_filename: None,
169 log_filename: None,
170 platform_name: None,
171 renderer_name: None,
172 clipboard_ctx: Box::new(ClipboardContext::dummy()),
173 ui,
174 })
175 }
176
177 pub fn io_mut(&mut self) -> &mut Io {
179 let _guard = CTX_MUTEX.lock();
180 unsafe {
181 let io_ptr = self.io_ptr("Context::io_mut()");
182 &mut *(io_ptr as *mut Io)
183 }
184 }
185
186 pub fn io(&self) -> &crate::io::Io {
188 let _guard = CTX_MUTEX.lock();
189 unsafe {
190 let io_ptr = self.io_ptr("Context::io()");
191 &*(io_ptr as *const crate::io::Io)
192 }
193 }
194
195 pub fn style(&self) -> &crate::style::Style {
197 let _guard = CTX_MUTEX.lock();
198 unsafe {
199 with_bound_context(self.raw, || {
200 let style_ptr = sys::igGetStyle();
201 if style_ptr.is_null() {
202 panic!("Context::style() requires a valid ImGui context");
203 }
204 &*(style_ptr as *const crate::style::Style)
205 })
206 }
207 }
208
209 pub fn style_mut(&mut self) -> &mut crate::style::Style {
211 let _guard = CTX_MUTEX.lock();
212 unsafe {
213 with_bound_context(self.raw, || {
214 let style_ptr = sys::igGetStyle();
215 if style_ptr.is_null() {
216 panic!("Context::style_mut() requires a valid ImGui context");
217 }
218 &mut *(style_ptr as *mut crate::style::Style)
219 })
220 }
221 }
222
223 pub(super) fn is_current_context(&self) -> bool {
224 let ctx = unsafe { sys::igGetCurrentContext() };
225 self.raw == ctx
226 }
227}
228
229impl Drop for Context {
230 fn drop(&mut self) {
231 let _guard = CTX_MUTEX.lock();
232 unsafe {
233 if !self.raw.is_null() {
234 unregister_user_textures_for_context(self.raw);
235 if self.shared_font_atlas.is_none() {
236 let io = sys::igGetIO_ContextPtr(self.raw);
237 if !io.is_null() {
238 crate::fonts::forget_font_atlas_generation((*io).Fonts);
239 }
240 }
241 crate::platform_io::clear_typed_callbacks_for_context(self.raw);
242 with_bound_context(self.raw, || {
243 crate::platform_io::clear_out_param_callbacks_for_current_context();
244 });
245 if sys::igGetCurrentContext() == self.raw {
246 clear_current_context();
247 }
248 sys::igDestroyContext(self.raw);
249 }
250 }
251 }
252}