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