1use libc::{c_char, c_int};
4use std::mem;
5
6use glib::object::IsA;
7use glib::subclass::prelude::*;
8use glib::translate::*;
9use glib::Cast;
10use glib::GString;
11
12use crate::CellEditable;
13use crate::CellRenderer;
14use crate::CellRendererState;
15use crate::SizeRequestMode;
16use crate::Widget;
17
18pub trait CellRendererImpl: CellRendererImplExt + ObjectImpl {
19 fn request_mode(&self) -> SizeRequestMode {
26 self.parent_request_mode()
27 }
28
29 fn preferred_width<P: IsA<Widget>>(&self, widget: &P) -> (i32, i32) {
42 self.parent_preferred_width(widget)
43 }
44
45 #[doc(alias = "get_preferred_width_for_height")]
61 fn preferred_width_for_height<P: IsA<Widget>>(&self, widget: &P, height: i32) -> (i32, i32) {
62 self.parent_preferred_width_for_height(widget, height)
63 }
64
65 #[doc(alias = "get_preferred_height")]
78 fn preferred_height<P: IsA<Widget>>(&self, widget: &P) -> (i32, i32) {
79 self.parent_preferred_height(widget)
80 }
81
82 #[doc(alias = "get_preferred_height_for_width")]
98 fn preferred_height_for_width<P: IsA<Widget>>(&self, widget: &P, width: i32) -> (i32, i32) {
99 self.parent_preferred_height_for_width(widget, width)
100 }
101
102 #[doc(alias = "get_aligned_area")]
118 fn aligned_area<P: IsA<Widget>>(
119 &self,
120 widget: &P,
121 flags: CellRendererState,
122 cell_area: &gdk::Rectangle,
123 ) -> gdk::Rectangle {
124 self.parent_aligned_area(widget, flags, cell_area)
125 }
126
127 fn render<P: IsA<Widget>>(
146 &self,
147 cr: &cairo::Context,
148 widget: &P,
149 background_area: &gdk::Rectangle,
150 cell_area: &gdk::Rectangle,
151 flags: CellRendererState,
152 ) {
153 self.parent_render(cr, widget, background_area, cell_area, flags);
154 }
155
156 fn activate<P: IsA<Widget>>(
177 &self,
178 event: Option<&gdk::Event>,
179 widget: &P,
180 path: &str,
181 background_area: &gdk::Rectangle,
182 cell_area: &gdk::Rectangle,
183 flags: CellRendererState,
184 ) -> bool {
185 self.parent_activate(event, widget, path, background_area, cell_area, flags)
186 }
187
188 fn start_editing<P: IsA<Widget>>(
209 &self,
210 event: Option<&gdk::Event>,
211 widget: &P,
212 path: &str,
213 background_area: &gdk::Rectangle,
214 cell_area: &gdk::Rectangle,
215 flags: CellRendererState,
216 ) -> Option<CellEditable> {
217 self.parent_start_editing(event, widget, path, background_area, cell_area, flags)
218 }
219
220 fn editing_canceled(&self) {
221 self.parent_editing_canceled()
222 }
223
224 fn editing_started(&self, editable: &CellEditable, path: &str) {
225 self.parent_editing_started(editable, path)
226 }
227}
228
229mod sealed {
230 pub trait Sealed {}
231 impl<T: super::CellRendererImpl> Sealed for T {}
232}
233
234pub trait CellRendererImplExt: ObjectSubclass + sealed::Sealed {
235 fn parent_request_mode(&self) -> SizeRequestMode {
236 unsafe {
237 let data = Self::type_data();
238 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
239 let f = (*parent_class).get_request_mode.unwrap();
240 from_glib(f(self
241 .obj()
242 .unsafe_cast_ref::<CellRenderer>()
243 .to_glib_none()
244 .0))
245 }
246 }
247 fn parent_preferred_width<P: IsA<Widget>>(&self, widget: &P) -> (i32, i32) {
248 unsafe {
249 let data = Self::type_data();
250 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
251 let f = (*parent_class).get_preferred_width.unwrap();
252
253 let mut minimum_size = mem::MaybeUninit::uninit();
254 let mut natural_size = mem::MaybeUninit::uninit();
255 f(
256 self.obj()
257 .unsafe_cast_ref::<CellRenderer>()
258 .to_glib_none()
259 .0,
260 widget.as_ref().to_glib_none().0,
261 minimum_size.as_mut_ptr(),
262 natural_size.as_mut_ptr(),
263 );
264 (minimum_size.assume_init(), natural_size.assume_init())
265 }
266 }
267 fn parent_preferred_width_for_height<P: IsA<Widget>>(
268 &self,
269 widget: &P,
270 height: i32,
271 ) -> (i32, i32) {
272 unsafe {
273 let data = Self::type_data();
274 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
275 let f = (*parent_class).get_preferred_width_for_height.unwrap();
276
277 let mut minimum_size = mem::MaybeUninit::uninit();
278 let mut natural_size = mem::MaybeUninit::uninit();
279 f(
280 self.obj()
281 .unsafe_cast_ref::<CellRenderer>()
282 .to_glib_none()
283 .0,
284 widget.as_ref().to_glib_none().0,
285 height,
286 minimum_size.as_mut_ptr(),
287 natural_size.as_mut_ptr(),
288 );
289 (minimum_size.assume_init(), natural_size.assume_init())
290 }
291 }
292 fn parent_preferred_height<P: IsA<Widget>>(&self, widget: &P) -> (i32, i32) {
293 unsafe {
294 let data = Self::type_data();
295 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
296 let f = (*parent_class).get_preferred_height.unwrap();
297 let mut minimum_size = mem::MaybeUninit::uninit();
298 let mut natural_size = mem::MaybeUninit::uninit();
299 f(
300 self.obj()
301 .unsafe_cast_ref::<CellRenderer>()
302 .to_glib_none()
303 .0,
304 widget.as_ref().to_glib_none().0,
305 minimum_size.as_mut_ptr(),
306 natural_size.as_mut_ptr(),
307 );
308 (minimum_size.assume_init(), natural_size.assume_init())
309 }
310 }
311 fn parent_preferred_height_for_width<P: IsA<Widget>>(
312 &self,
313 widget: &P,
314 width: i32,
315 ) -> (i32, i32) {
316 unsafe {
317 let data = Self::type_data();
318 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
319 let f = (*parent_class).get_preferred_height_for_width.unwrap();
320 let mut minimum_size = mem::MaybeUninit::uninit();
321 let mut natural_size = mem::MaybeUninit::uninit();
322 f(
323 self.obj()
324 .unsafe_cast_ref::<CellRenderer>()
325 .to_glib_none()
326 .0,
327 widget.as_ref().to_glib_none().0,
328 width,
329 minimum_size.as_mut_ptr(),
330 natural_size.as_mut_ptr(),
331 );
332 (minimum_size.assume_init(), natural_size.assume_init())
333 }
334 }
335 fn parent_aligned_area<P: IsA<Widget>>(
336 &self,
337 widget: &P,
338 flags: CellRendererState,
339 cell_area: &gdk::Rectangle,
340 ) -> gdk::Rectangle {
341 unsafe {
342 let data = Self::type_data();
343 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
344 let mut aligned_area = gdk::Rectangle::uninitialized();
345 let f = (*parent_class).get_aligned_area.unwrap();
346 f(
347 self.obj()
348 .unsafe_cast_ref::<CellRenderer>()
349 .to_glib_none()
350 .0,
351 widget.as_ref().to_glib_none().0,
352 flags.into_glib(),
353 cell_area.to_glib_none().0,
354 aligned_area.to_glib_none_mut().0,
355 );
356 aligned_area
357 }
358 }
359 fn parent_render<P: IsA<Widget>>(
360 &self,
361 cr: &cairo::Context,
362 widget: &P,
363 background_area: &gdk::Rectangle,
364 cell_area: &gdk::Rectangle,
365 flags: CellRendererState,
366 ) {
367 unsafe {
368 let data = Self::type_data();
369 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
370 if let Some(f) = (*parent_class).render {
371 f(
372 self.obj()
373 .unsafe_cast_ref::<CellRenderer>()
374 .to_glib_none()
375 .0,
376 cr.to_glib_none().0,
377 widget.as_ref().to_glib_none().0,
378 background_area.to_glib_none().0,
379 cell_area.to_glib_none().0,
380 flags.into_glib(),
381 )
382 }
383 }
384 }
385 fn parent_activate<P: IsA<Widget>>(
386 &self,
387 event: Option<&gdk::Event>,
388 widget: &P,
389 path: &str,
390 background_area: &gdk::Rectangle,
391 cell_area: &gdk::Rectangle,
392 flags: CellRendererState,
393 ) -> bool {
394 unsafe {
395 let data = Self::type_data();
396 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
397 if let Some(f) = (*parent_class).activate {
398 from_glib(f(
399 self.obj()
400 .unsafe_cast_ref::<CellRenderer>()
401 .to_glib_none()
402 .0,
403 mut_override(event.to_glib_none().0),
404 widget.as_ref().to_glib_none().0,
405 path.to_glib_none().0,
406 background_area.to_glib_none().0,
407 cell_area.to_glib_none().0,
408 flags.into_glib(),
409 ))
410 } else {
411 false
412 }
413 }
414 }
415 fn parent_start_editing<P: IsA<Widget>>(
416 &self,
417 event: Option<&gdk::Event>,
418 widget: &P,
419 path: &str,
420 background_area: &gdk::Rectangle,
421 cell_area: &gdk::Rectangle,
422 flags: CellRendererState,
423 ) -> Option<CellEditable> {
424 unsafe {
425 let data = Self::type_data();
426 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
427 if let Some(f) = (*parent_class).start_editing {
428 from_glib_none(f(
429 self.obj()
430 .unsafe_cast_ref::<CellRenderer>()
431 .to_glib_none()
432 .0,
433 mut_override(event.to_glib_none().0),
434 widget.as_ref().to_glib_none().0,
435 path.to_glib_none().0,
436 background_area.to_glib_none().0,
437 cell_area.to_glib_none().0,
438 flags.into_glib(),
439 ))
440 } else {
441 None
442 }
443 }
444 }
445 fn parent_editing_canceled(&self) {
446 unsafe {
447 let data = Self::type_data();
448 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
449 if let Some(f) = (*parent_class).editing_canceled {
450 f(self
451 .obj()
452 .unsafe_cast_ref::<CellRenderer>()
453 .to_glib_none()
454 .0)
455 }
456 }
457 }
458 fn parent_editing_started(&self, editable: &CellEditable, path: &str) {
459 unsafe {
460 let data = Self::type_data();
461 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
462 if let Some(f) = (*parent_class).editing_started {
463 f(
464 self.obj()
465 .unsafe_cast_ref::<CellRenderer>()
466 .to_glib_none()
467 .0,
468 editable.to_glib_none().0,
469 path.to_glib_none().0,
470 )
471 }
472 }
473 }
474}
475
476impl<T: CellRendererImpl> CellRendererImplExt for T {}
477
478unsafe impl<T: CellRendererImpl> IsSubclassable<T> for CellRenderer {
479 fn class_init(class: &mut ::glib::Class<Self>) {
480 Self::parent_class_init::<T>(class);
481
482 if !crate::rt::is_initialized() {
483 panic!("GTK has to be initialized first");
484 }
485
486 let klass = class.as_mut();
487 klass.get_request_mode = Some(cell_renderer_get_request_mode::<T>);
488 klass.get_preferred_width = Some(cell_renderer_get_preferred_width::<T>);
489 klass.get_preferred_height_for_width =
490 Some(cell_renderer_get_preferred_height_for_width::<T>);
491 klass.get_preferred_height = Some(cell_renderer_get_preferred_height::<T>);
492 klass.get_preferred_width_for_height =
493 Some(cell_renderer_get_preferred_width_for_height::<T>);
494 klass.get_aligned_area = Some(cell_renderer_get_aligned_area::<T>);
495 klass.render = Some(cell_renderer_render::<T>);
496 klass.activate = Some(cell_renderer_activate::<T>);
497 klass.start_editing = Some(cell_renderer_start_editing::<T>);
498 klass.editing_started = Some(cell_renderer_editing_started::<T>);
499 klass.editing_canceled = Some(cell_renderer_editing_canceled::<T>);
500 }
501}
502
503unsafe extern "C" fn cell_renderer_get_request_mode<T: CellRendererImpl>(
504 ptr: *mut ffi::GtkCellRenderer,
505) -> ffi::GtkSizeRequestMode {
506 let instance = &*(ptr as *mut T::Instance);
507 let imp = instance.imp();
508
509 imp.request_mode().into_glib()
510}
511
512unsafe extern "C" fn cell_renderer_get_preferred_width<T: CellRendererImpl>(
513 ptr: *mut ffi::GtkCellRenderer,
514 wdgtptr: *mut ffi::GtkWidget,
515 minptr: *mut c_int,
516 natptr: *mut c_int,
517) {
518 let instance = &*(ptr as *mut T::Instance);
519 let imp = instance.imp();
520 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
521
522 let (min_size, nat_size) = imp.preferred_width(&*widget);
523 if !minptr.is_null() {
524 *minptr = min_size;
525 }
526 if !natptr.is_null() {
527 *natptr = nat_size;
528 }
529}
530
531unsafe extern "C" fn cell_renderer_get_preferred_height_for_width<T: CellRendererImpl>(
532 ptr: *mut ffi::GtkCellRenderer,
533 wdgtptr: *mut ffi::GtkWidget,
534 width: c_int,
535 min_height_ptr: *mut c_int,
536 nat_height_ptr: *mut c_int,
537) {
538 let instance = &*(ptr as *mut T::Instance);
539 let imp = instance.imp();
540 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
541
542 let (min_height, nat_height) = imp.preferred_height_for_width(&*widget, width);
543 if !min_height_ptr.is_null() {
544 *min_height_ptr = min_height;
545 }
546 if !nat_height_ptr.is_null() {
547 *nat_height_ptr = nat_height;
548 }
549}
550
551unsafe extern "C" fn cell_renderer_get_preferred_height<T: CellRendererImpl>(
552 ptr: *mut ffi::GtkCellRenderer,
553 wdgtptr: *mut ffi::GtkWidget,
554 minptr: *mut c_int,
555 natptr: *mut c_int,
556) {
557 let instance = &*(ptr as *mut T::Instance);
558 let imp = instance.imp();
559 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
560
561 let (min_size, nat_size) = imp.preferred_height(&*widget);
562 if !minptr.is_null() {
563 *minptr = min_size;
564 }
565 if !natptr.is_null() {
566 *natptr = nat_size;
567 }
568}
569
570unsafe extern "C" fn cell_renderer_get_preferred_width_for_height<T: CellRendererImpl>(
571 ptr: *mut ffi::GtkCellRenderer,
572 wdgtptr: *mut ffi::GtkWidget,
573 height: c_int,
574 min_width_ptr: *mut c_int,
575 nat_width_ptr: *mut c_int,
576) {
577 let instance = &*(ptr as *mut T::Instance);
578 let imp = instance.imp();
579 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
580
581 let (min_width, nat_width) = imp.preferred_width_for_height(&*widget, height);
582 if !min_width_ptr.is_null() {
583 *min_width_ptr = min_width;
584 }
585 if !nat_width_ptr.is_null() {
586 *nat_width_ptr = nat_width;
587 }
588}
589
590unsafe extern "C" fn cell_renderer_get_aligned_area<T: CellRendererImpl>(
591 ptr: *mut ffi::GtkCellRenderer,
592 wdgtptr: *mut ffi::GtkWidget,
593 flags: ffi::GtkCellRendererState,
594 cellarea: *const gdk::ffi::GdkRectangle,
595 alignedptr: *mut gdk::ffi::GdkRectangle,
596) {
597 let instance = &*(ptr as *mut T::Instance);
598 let imp = instance.imp();
599 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
600
601 let rectangle = imp.aligned_area(&*widget, from_glib(flags), &from_glib_borrow(cellarea));
602 *alignedptr = *rectangle.to_glib_none().0;
603}
604
605unsafe extern "C" fn cell_renderer_render<T: CellRendererImpl>(
606 ptr: *mut ffi::GtkCellRenderer,
607 crptr: *mut cairo::ffi::cairo_t,
608 wdgtptr: *mut ffi::GtkWidget,
609 bgptr: *const gdk::ffi::GdkRectangle,
610 cellptr: *const gdk::ffi::GdkRectangle,
611 flags: ffi::GtkCellRendererState,
612) {
613 let instance = &*(ptr as *mut T::Instance);
614 let imp = instance.imp();
615 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
616 let cr: Borrowed<cairo::Context> = from_glib_borrow(crptr);
617
618 imp.render(
619 &cr,
620 &*widget,
621 &from_glib_borrow(bgptr),
622 &from_glib_borrow(cellptr),
623 from_glib(flags),
624 );
625}
626
627unsafe extern "C" fn cell_renderer_activate<T: CellRendererImpl>(
628 ptr: *mut ffi::GtkCellRenderer,
629 evtptr: *mut gdk::ffi::GdkEvent,
630 wdgtptr: *mut ffi::GtkWidget,
631 pathptr: *const c_char,
632 bgptr: *const gdk::ffi::GdkRectangle,
633 cellptr: *const gdk::ffi::GdkRectangle,
634 flags: ffi::GtkCellRendererState,
635) -> glib::ffi::gboolean {
636 let instance = &*(ptr as *mut T::Instance);
637 let imp = instance.imp();
638 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
639 let evt: Borrowed<Option<gdk::Event>> = from_glib_borrow(evtptr);
640
641 imp.activate(
642 evt.as_ref().as_ref(),
643 &*widget,
644 &GString::from_glib_borrow(pathptr),
645 &from_glib_borrow(bgptr),
646 &from_glib_borrow(cellptr),
647 from_glib(flags),
648 )
649 .into_glib()
650}
651
652unsafe extern "C" fn cell_renderer_start_editing<T: CellRendererImpl>(
653 ptr: *mut ffi::GtkCellRenderer,
654 evtptr: *mut gdk::ffi::GdkEvent,
655 wdgtptr: *mut ffi::GtkWidget,
656 pathptr: *const c_char,
657 bgptr: *const gdk::ffi::GdkRectangle,
658 cellptr: *const gdk::ffi::GdkRectangle,
659 flags: ffi::GtkCellRendererState,
660) -> *mut ffi::GtkCellEditable {
661 let instance = &*(ptr as *mut T::Instance);
662 let imp = instance.imp();
663 let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
664 let evt: Borrowed<Option<gdk::Event>> = from_glib_borrow(evtptr);
665
666 imp.start_editing(
667 evt.as_ref().as_ref(),
668 &*widget,
669 &GString::from_glib_borrow(pathptr),
670 &from_glib_borrow(bgptr),
671 &from_glib_borrow(cellptr),
672 from_glib(flags),
673 )
674 .to_glib_none()
675 .0
676}
677
678unsafe extern "C" fn cell_renderer_editing_canceled<T: CellRendererImpl>(
679 ptr: *mut ffi::GtkCellRenderer,
680) {
681 let instance = &*(ptr as *mut T::Instance);
682 let imp = instance.imp();
683
684 imp.editing_canceled();
685}
686
687unsafe extern "C" fn cell_renderer_editing_started<T: CellRendererImpl>(
688 ptr: *mut ffi::GtkCellRenderer,
689 editableptr: *mut ffi::GtkCellEditable,
690 pathptr: *const c_char,
691) {
692 let instance = &*(ptr as *mut T::Instance);
693 let imp = instance.imp();
694 let editable = from_glib_borrow(editableptr);
695
696 imp.editing_started(&editable, &GString::from_glib_borrow(pathptr));
697}