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