dear_imgui_rs/context/
texture_registry.rs1use std::cell::RefCell;
2use std::rc::{Rc, Weak};
3
4use crate::sys;
5
6use super::Context;
7use super::binding::{CTX_MUTEX, with_bound_context};
8
9#[derive(Clone)]
10struct UserTextureRegistration {
11 ctx: *mut sys::ImGuiContext,
12 tex: *mut sys::ImTextureData,
13 alive: Weak<()>,
14}
15
16thread_local! {
17 static USER_TEXTURE_REGISTRATIONS: RefCell<Vec<UserTextureRegistration>> = RefCell::new(Vec::new());
18}
19
20fn prune_dead_user_texture_registrations(registrations: &mut Vec<UserTextureRegistration>) {
21 registrations.retain(|registration| registration.alive.upgrade().is_some());
22}
23
24fn is_user_texture_registered(ctx: *mut sys::ImGuiContext, tex: *mut sys::ImTextureData) -> bool {
25 USER_TEXTURE_REGISTRATIONS.with(|registrations| {
26 let mut registrations = registrations.borrow_mut();
27 prune_dead_user_texture_registrations(&mut registrations);
28 registrations
29 .iter()
30 .any(|registration| registration.ctx == ctx && registration.tex == tex)
31 })
32}
33
34fn track_user_texture_registration(
35 ctx: *mut sys::ImGuiContext,
36 tex: *mut sys::ImTextureData,
37 alive: Weak<()>,
38) {
39 USER_TEXTURE_REGISTRATIONS.with(|registrations| {
40 let mut registrations = registrations.borrow_mut();
41 prune_dead_user_texture_registrations(&mut registrations);
42 registrations.push(UserTextureRegistration { ctx, tex, alive });
43 });
44}
45
46fn take_user_texture_registration(
47 ctx: *mut sys::ImGuiContext,
48 tex: *mut sys::ImTextureData,
49) -> Option<UserTextureRegistration> {
50 USER_TEXTURE_REGISTRATIONS.with(|registrations| {
51 let mut registrations = registrations.borrow_mut();
52 prune_dead_user_texture_registrations(&mut registrations);
53 registrations
54 .iter()
55 .position(|registration| registration.ctx == ctx && registration.tex == tex)
56 .map(|index| registrations.remove(index))
57 })
58}
59
60fn unregister_user_texture_registration(registration: UserTextureRegistration) {
61 if registration.ctx.is_null()
62 || registration.tex.is_null()
63 || registration.alive.upgrade().is_none()
64 {
65 return;
66 }
67
68 unsafe {
69 with_bound_context(registration.ctx, || {
70 sys::igUnregisterUserTexture(registration.tex);
71 });
72 }
73}
74
75pub(crate) fn unregister_user_texture_from_all_contexts(tex: *mut sys::ImTextureData) {
76 if tex.is_null() {
77 return;
78 }
79
80 let registrations = USER_TEXTURE_REGISTRATIONS.with(|registrations| {
81 let mut registrations = registrations.borrow_mut();
82 let mut taken = Vec::new();
83 let mut index = 0;
84 while index < registrations.len() {
85 if registrations[index].alive.upgrade().is_none() {
86 registrations.remove(index);
87 } else if registrations[index].tex == tex {
88 taken.push(registrations.remove(index));
89 } else {
90 index += 1;
91 }
92 }
93 taken
94 });
95
96 let _guard = CTX_MUTEX.lock();
97 for registration in registrations {
98 unregister_user_texture_registration(registration);
99 }
100}
101
102pub(super) fn unregister_user_textures_for_context(ctx: *mut sys::ImGuiContext) {
103 if ctx.is_null() {
104 return;
105 }
106
107 let registrations = USER_TEXTURE_REGISTRATIONS.with(|registrations| {
108 let mut registrations = registrations.borrow_mut();
109 let mut taken = Vec::new();
110 let mut index = 0;
111 while index < registrations.len() {
112 if registrations[index].alive.upgrade().is_none() || registrations[index].ctx == ctx {
113 let registration = registrations.remove(index);
114 if registration.ctx == ctx {
115 taken.push(registration);
116 }
117 } else {
118 index += 1;
119 }
120 }
121 taken
122 });
123
124 for registration in registrations {
125 unregister_user_texture_registration(registration);
126 }
127}
128
129impl Context {
130 pub fn register_user_texture(&mut self, texture: &mut crate::texture::OwnedTextureData) {
142 self.register_user_texture_ptr(texture.as_mut().as_raw_mut());
143 }
144
145 pub unsafe fn register_user_texture_raw(&mut self, texture: &mut crate::texture::TextureData) {
154 self.register_user_texture_ptr(texture.as_raw_mut());
155 }
156
157 fn register_user_texture_ptr(&mut self, texture: *mut sys::ImTextureData) {
158 let _guard = CTX_MUTEX.lock();
159 self.assert_current_context("Context::register_user_texture()");
160 assert!(
161 !texture.is_null(),
162 "Context::register_user_texture() received a null texture"
163 );
164 if is_user_texture_registered(self.raw, texture) {
165 return;
166 }
167 unsafe {
168 sys::igRegisterUserTexture(texture);
169 }
170 track_user_texture_registration(self.raw, texture, Rc::downgrade(&self.alive));
171 }
172
173 pub fn register_user_texture_token(
177 &mut self,
178 texture: &mut crate::texture::OwnedTextureData,
179 ) -> RegisteredUserTexture {
180 self.register_user_texture(texture);
181 RegisteredUserTexture {
182 ctx: self.raw,
183 tex: texture.as_mut().as_raw_mut(),
184 alive: Rc::downgrade(&self.alive),
185 }
186 }
187
188 pub fn unregister_user_texture(&mut self, texture: &mut crate::texture::OwnedTextureData) {
192 self.unregister_user_texture_ptr(texture.as_mut().as_raw_mut());
193 }
194
195 pub unsafe fn unregister_user_texture_raw(
202 &mut self,
203 texture: &mut crate::texture::TextureData,
204 ) {
205 self.unregister_user_texture_ptr(texture.as_raw_mut());
206 }
207
208 fn unregister_user_texture_ptr(&mut self, texture: *mut sys::ImTextureData) {
209 let _guard = CTX_MUTEX.lock();
210 self.assert_current_context("Context::unregister_user_texture()");
211 assert!(
212 !texture.is_null(),
213 "Context::unregister_user_texture() received a null texture"
214 );
215 if let Some(registration) = take_user_texture_registration(self.raw, texture) {
216 unregister_user_texture_registration(registration);
217 }
218 }
219}
220
221#[derive(Debug)]
226pub struct RegisteredUserTexture {
227 ctx: *mut sys::ImGuiContext,
228 tex: *mut sys::ImTextureData,
229 alive: Weak<()>,
230}
231
232impl Drop for RegisteredUserTexture {
233 fn drop(&mut self) {
234 if self.ctx.is_null() || self.tex.is_null() || self.alive.upgrade().is_none() {
235 return;
236 }
237
238 let _guard = CTX_MUTEX.lock();
239 if let Some(registration) = take_user_texture_registration(self.ctx, self.tex) {
240 unregister_user_texture_registration(registration);
241 }
242 }
243}