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 fn is_alive(&self) -> bool {
60 self.0.upgrade().is_some()
61 }
62}
63
64impl Context {
65 pub fn try_create() -> crate::error::ImGuiResult<Context> {
69 Self::try_create_internal(None)
70 }
71
72 pub fn try_create_with_shared_font_atlas(
74 shared_font_atlas: SharedFontAtlas,
75 ) -> crate::error::ImGuiResult<Context> {
76 Self::try_create_internal(Some(shared_font_atlas))
77 }
78
79 pub fn create() -> Context {
83 Self::try_create().expect("Failed to create Dear ImGui context")
84 }
85
86 pub fn create_with_shared_font_atlas(shared_font_atlas: SharedFontAtlas) -> Context {
88 Self::try_create_with_shared_font_atlas(shared_font_atlas)
89 .expect("Failed to create Dear ImGui context")
90 }
91
92 pub fn as_raw(&self) -> *mut sys::ImGuiContext {
94 self.raw
95 }
96
97 pub fn alive_token(&self) -> ContextAliveToken {
102 ContextAliveToken(Rc::downgrade(&self.alive))
103 }
104
105 pub(super) fn io_ptr(&self, caller: &str) -> *mut sys::ImGuiIO {
108 let io = unsafe { sys::igGetIO_ContextPtr(self.raw) };
109 if io.is_null() {
110 panic!("{caller} requires a valid ImGui context");
111 }
112 io
113 }
114
115 pub(super) fn platform_io_ptr(&self, caller: &str) -> *mut sys::ImGuiPlatformIO {
116 let pio = unsafe { sys::igGetPlatformIO_ContextPtr(self.raw) };
117 if pio.is_null() {
118 panic!("{caller} requires a valid ImGui context");
119 }
120 pio
121 }
122
123 pub(super) fn assert_current_context(&self, caller: &str) {
124 assert!(
125 self.is_current_context(),
126 "{caller} requires this context to be current"
127 );
128 }
129
130 fn try_create_internal(
131 mut shared_font_atlas: Option<SharedFontAtlas>,
132 ) -> crate::error::ImGuiResult<Context> {
133 let _guard = CTX_MUTEX.lock();
134
135 if !no_current_context() {
136 return Err(crate::error::ImGuiError::ContextAlreadyActive);
137 }
138
139 let shared_font_atlas_ptr = match &mut shared_font_atlas {
140 Some(atlas) => atlas.as_ptr_mut(),
141 None => ptr::null_mut(),
142 };
143
144 let raw = unsafe { sys::igCreateContext(shared_font_atlas_ptr) };
146 if raw.is_null() {
147 return Err(crate::error::ImGuiError::ContextCreation {
148 reason: "ImGui_CreateContext returned null".to_string(),
149 });
150 }
151
152 unsafe {
154 sys::igSetCurrentContext(raw);
155 }
156
157 Ok(Context {
158 raw,
159 alive: Rc::new(()),
160 shared_font_atlas,
161 ini_filename: None,
162 log_filename: None,
163 platform_name: None,
164 renderer_name: None,
165 clipboard_ctx: Box::new(ClipboardContext::dummy()),
166 ui: crate::ui::Ui::new(),
167 })
168 }
169
170 pub fn io_mut(&mut self) -> &mut Io {
172 let _guard = CTX_MUTEX.lock();
173 unsafe {
174 let io_ptr = self.io_ptr("Context::io_mut()");
175 &mut *(io_ptr as *mut Io)
176 }
177 }
178
179 pub fn io(&self) -> &crate::io::Io {
181 let _guard = CTX_MUTEX.lock();
182 unsafe {
183 let io_ptr = self.io_ptr("Context::io()");
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 with_bound_context(self.raw, || {
193 let style_ptr = sys::igGetStyle();
194 if style_ptr.is_null() {
195 panic!("Context::style() requires a valid ImGui context");
196 }
197 &*(style_ptr as *const crate::style::Style)
198 })
199 }
200 }
201
202 pub fn style_mut(&mut self) -> &mut crate::style::Style {
204 let _guard = CTX_MUTEX.lock();
205 unsafe {
206 with_bound_context(self.raw, || {
207 let style_ptr = sys::igGetStyle();
208 if style_ptr.is_null() {
209 panic!("Context::style_mut() requires a valid ImGui context");
210 }
211 &mut *(style_ptr as *mut crate::style::Style)
212 })
213 }
214 }
215
216 pub(super) fn is_current_context(&self) -> bool {
217 let ctx = unsafe { sys::igGetCurrentContext() };
218 self.raw == ctx
219 }
220}
221
222impl Drop for Context {
223 fn drop(&mut self) {
224 let _guard = CTX_MUTEX.lock();
225 unsafe {
226 if !self.raw.is_null() {
227 unregister_user_textures_for_context(self.raw);
228 if self.shared_font_atlas.is_none() {
229 let io = sys::igGetIO_ContextPtr(self.raw);
230 if !io.is_null() {
231 crate::fonts::forget_font_atlas_generation((*io).Fonts);
232 }
233 }
234 crate::platform_io::clear_typed_callbacks_for_context(self.raw);
235 with_bound_context(self.raw, || {
236 crate::platform_io::clear_out_param_callbacks_for_current_context();
237 });
238 if sys::igGetCurrentContext() == self.raw {
239 clear_current_context();
240 }
241 sys::igDestroyContext(self.raw);
242 }
243 }
244 }
245}