gtk/subclass/
container.rs1use std::ptr;
4
5use glib::{ParamSpec, Value, gobject_ffi, translate::*};
6
7use glib::subclass::prelude::*;
8
9use glib::object::Cast;
10
11use super::widget::WidgetImpl;
12use crate::Widget;
13use crate::WidgetPath;
14use crate::{Container, ffi};
15
16pub trait ContainerImpl: ContainerImplExt + WidgetImpl {
17 fn child_properties() -> &'static [ParamSpec] {
23 &[]
24 }
25
26 fn add(&self, widget: &Widget) {
41 self.parent_add(widget)
42 }
43
44 fn remove(&self, widget: &Widget) {
56 self.parent_remove(widget)
57 }
58
59 fn check_resize(&self) {
61 self.parent_check_resize()
62 }
63
64 fn set_focus_child(&self, widget: Option<&Widget>) {
75 self.parent_set_focus_child(widget)
76 }
77
78 fn child_type(&self) -> glib::Type {
88 self.parent_child_type()
89 }
90
91 #[doc(alias = "get_path_for_child")]
100 fn path_for_child(&self, widget: &Widget) -> WidgetPath {
101 self.parent_path_for_child(widget)
102 }
103
104 fn forall(&self, include_internals: bool, callback: &Callback) {
117 self.parent_forall(include_internals, callback);
118 }
119
120 fn set_child_property(&self, _child: &Widget, _id: usize, _value: &Value, _pspec: &ParamSpec) {
122 unimplemented!()
123 }
124
125 #[doc(alias = "get_child_property")]
127 fn child_property(&self, _child: &Widget, _id: usize, _pspec: &ParamSpec) -> Value {
128 unimplemented!()
129 }
130}
131
132mod sealed {
133 pub trait Sealed {}
134 impl<T: super::ContainerImpl> Sealed for T {}
135}
136
137pub trait ContainerImplExt: ObjectSubclass + sealed::Sealed {
138 fn parent_add(&self, widget: &Widget) {
139 unsafe {
140 let data = Self::type_data();
141 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkContainerClass;
142 if let Some(f) = (*parent_class).add {
143 f(
144 self.obj().unsafe_cast_ref::<Container>().to_glib_none().0,
145 widget.to_glib_none().0,
146 )
147 }
148 }
149 }
150 fn parent_remove(&self, widget: &Widget) {
151 unsafe {
152 let data = Self::type_data();
153 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkContainerClass;
154 if let Some(f) = (*parent_class).remove {
155 f(
156 self.obj().unsafe_cast_ref::<Container>().to_glib_none().0,
157 widget.to_glib_none().0,
158 )
159 }
160 }
161 }
162 fn parent_check_resize(&self) {
163 unsafe {
164 let data = Self::type_data();
165 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkContainerClass;
166 if let Some(f) = (*parent_class).check_resize {
167 f(self.obj().unsafe_cast_ref::<Container>().to_glib_none().0)
168 }
169 }
170 }
171 fn parent_set_focus_child(&self, widget: Option<&Widget>) {
172 unsafe {
173 let data = Self::type_data();
174 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkContainerClass;
175 if let Some(f) = (*parent_class).set_focus_child {
176 f(
177 self.obj().unsafe_cast_ref::<Container>().to_glib_none().0,
178 widget.to_glib_none().0,
179 )
180 }
181 }
182 }
183 fn parent_child_type(&self) -> glib::Type {
184 unsafe {
185 let data = Self::type_data();
186 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkContainerClass;
187 if let Some(f) = (*parent_class).child_type {
188 from_glib(f(self
189 .obj()
190 .unsafe_cast_ref::<Container>()
191 .to_glib_none()
192 .0))
193 } else {
194 glib::Type::UNIT
195 }
196 }
197 }
198 fn parent_path_for_child(&self, widget: &Widget) -> WidgetPath {
199 unsafe {
200 let data = Self::type_data();
201 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkContainerClass;
202 let f = (*parent_class)
203 .get_path_for_child
204 .expect("No parent class impl for \"get_path_for_child\"");
205 from_glib_none(f(
206 self.obj().unsafe_cast_ref::<Container>().to_glib_none().0,
207 widget.to_glib_none().0,
208 ))
209 }
210 }
211 fn parent_forall(&self, include_internals: bool, callback: &Callback) {
212 unsafe {
213 let data = Self::type_data();
214 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkContainerClass;
215 if let Some(f) = (*parent_class).forall {
216 f(
217 self.obj().unsafe_cast_ref::<Container>().to_glib_none().0,
218 include_internals.into_glib(),
219 callback.callback,
220 callback.user_data,
221 )
222 }
223 }
224 }
225}
226
227impl<T: ContainerImpl> ContainerImplExt for T {}
228
229unsafe impl<T: ContainerImpl> IsSubclassable<T> for Container {
230 fn class_init(class: &mut ::glib::Class<Self>) {
231 Self::parent_class_init::<T>(class);
232
233 if !crate::rt::is_initialized() {
234 panic!("GTK has to be initialized first");
235 }
236
237 let klass = class.as_mut();
238 klass.add = Some(container_add::<T>);
239 klass.remove = Some(container_remove::<T>);
240 klass.check_resize = Some(container_check_resize::<T>);
241 klass.set_focus_child = Some(container_set_focus_child::<T>);
242 klass.child_type = Some(container_child_type::<T>);
243 klass.get_path_for_child = Some(container_get_path_for_child::<T>);
244 klass.forall = Some(container_forall::<T>);
245 klass.set_child_property = Some(container_set_child_property::<T>);
246 klass.get_child_property = Some(container_get_child_property::<T>);
247
248 let pspecs = <T as ContainerImpl>::child_properties();
249 if !pspecs.is_empty() {
250 unsafe {
251 let mut pspecs_ptrs = std::iter::once(ptr::null_mut())
252 .chain(pspecs.iter().map(|pspec| pspec.to_glib_none().0))
253 .collect::<Vec<_>>();
254 ffi::gtk_container_class_install_child_properties(
255 klass,
256 pspecs_ptrs.len() as u32,
257 pspecs_ptrs.as_mut_ptr(),
258 );
259 }
260 }
261 }
262}
263
264unsafe extern "C" fn container_add<T: ContainerImpl>(
265 ptr: *mut ffi::GtkContainer,
266 wdgtptr: *mut ffi::GtkWidget,
267) {
268 unsafe {
269 let instance = &*(ptr as *mut T::Instance);
270 let imp = instance.imp();
271 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
272
273 imp.add(&widget)
274 }
275}
276
277unsafe extern "C" fn container_remove<T: ContainerImpl>(
278 ptr: *mut ffi::GtkContainer,
279 wdgtptr: *mut ffi::GtkWidget,
280) {
281 unsafe {
282 let instance = &*(ptr as *mut T::Instance);
283 let imp = instance.imp();
284 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
285
286 imp.remove(&widget)
287 }
288}
289
290unsafe extern "C" fn container_check_resize<T: ContainerImpl>(ptr: *mut ffi::GtkContainer) {
291 unsafe {
292 let instance = &*(ptr as *mut T::Instance);
293 let imp = instance.imp();
294
295 imp.check_resize()
296 }
297}
298
299unsafe extern "C" fn container_set_focus_child<T: ContainerImpl>(
300 ptr: *mut ffi::GtkContainer,
301 wdgtptr: *mut ffi::GtkWidget,
302) {
303 unsafe {
304 let instance = &*(ptr as *mut T::Instance);
305 let imp = instance.imp();
306 let widget: Borrowed<Option<Widget>> = from_glib_borrow(wdgtptr);
307
308 imp.set_focus_child(widget.as_ref().as_ref())
309 }
310}
311
312unsafe extern "C" fn container_child_type<T: ContainerImpl>(
313 ptr: *mut ffi::GtkContainer,
314) -> glib::ffi::GType {
315 unsafe {
316 let instance = &*(ptr as *mut T::Instance);
317 let imp = instance.imp();
318
319 imp.child_type().into_glib()
320 }
321}
322
323unsafe extern "C" fn container_get_path_for_child<T: ContainerImpl>(
324 ptr: *mut ffi::GtkContainer,
325 wdgtptr: *mut ffi::GtkWidget,
326) -> *mut ffi::GtkWidgetPath {
327 unsafe {
328 let instance = &*(ptr as *mut T::Instance);
329 let imp = instance.imp();
330 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
331
332 imp.path_for_child(&widget).to_glib_none().0
333 }
334}
335
336unsafe extern "C" fn container_forall<T>(
337 ptr: *mut ffi::GtkContainer,
338 include_internals: glib::ffi::gboolean,
339 callback: ffi::GtkCallback,
340 user_data: glib::ffi::gpointer,
341) where
342 T: ObjectSubclass + ContainerImpl,
343{
344 unsafe {
345 let instance = &*(ptr as *mut T::Instance);
346 let imp = instance.imp();
347 let callback = Callback {
348 callback,
349 user_data,
350 };
351
352 imp.forall(from_glib(include_internals), &callback)
353 }
354}
355
356unsafe extern "C" fn container_set_child_property<T: ContainerImpl>(
357 ptr: *mut ffi::GtkContainer,
358 childptr: *mut ffi::GtkWidget,
359 property_id: libc::c_uint,
360 valueptr: *mut gobject_ffi::GValue,
361 pspecptr: *mut gobject_ffi::GParamSpec,
362) {
363 unsafe {
364 let instance = &*(ptr as *mut T::Instance);
365 let imp = instance.imp();
366 let child: Borrowed<Widget> = from_glib_borrow(childptr);
367 let value: Borrowed<glib::Value> = from_glib_borrow(valueptr);
368 let pspec: Borrowed<ParamSpec> = from_glib_borrow(pspecptr);
369
370 imp.set_child_property(&child, property_id as usize, &value, &pspec);
371 }
372}
373
374unsafe extern "C" fn container_get_child_property<T: ContainerImpl>(
375 ptr: *mut ffi::GtkContainer,
376 childptr: *mut ffi::GtkWidget,
377 property_id: libc::c_uint,
378 valueptr: *mut gobject_ffi::GValue,
379 pspecptr: *mut gobject_ffi::GParamSpec,
380) {
381 unsafe {
382 let instance = &*(ptr as *mut T::Instance);
383 let imp = instance.imp();
384 let child: Borrowed<Widget> = from_glib_borrow(childptr);
385 let pspec: Borrowed<ParamSpec> = from_glib_borrow(pspecptr);
386
387 let v = imp.child_property(&child, property_id as usize, &pspec);
388
389 gobject_ffi::g_value_unset(valueptr);
391 std::ptr::write(valueptr, v.into_raw());
393 }
394}
395
396#[derive(Debug)]
397pub struct Callback {
398 callback: ffi::GtkCallback,
399 user_data: glib::ffi::gpointer,
400}
401
402impl Callback {
403 pub fn call(&self, widget: &Widget) {
404 unsafe {
405 if let Some(callback) = self.callback {
406 callback(widget.to_glib_none().0, self.user_data);
407 }
408 }
409 }
410}
411
412pub unsafe trait ContainerClassSubclassExt: ClassStruct {
413 #[doc(alias = "gtk_container_class_handle_border_width")]
414 fn handle_border_width(&mut self) {
415 unsafe {
416 let widget_class = self as *mut _ as *mut ffi::GtkContainerClass;
417 ffi::gtk_container_class_handle_border_width(widget_class);
418 }
419 }
420}
421
422unsafe impl<T: ClassStruct> ContainerClassSubclassExt for T where T::Type: ContainerImpl {}