|
| 1 | +/// Public part of the BaseButton |
| 2 | +mod imp; |
| 3 | + |
| 4 | +pub use self::imp::PinnedFuture; |
| 5 | +use gtk::{ |
| 6 | + glib::{self, subclass::prelude::*}, |
| 7 | + prelude::*, |
| 8 | + subclass::prelude::*, |
| 9 | +}; |
| 10 | + |
| 11 | +glib::wrapper! { |
| 12 | + pub struct BaseButton(ObjectSubclass<imp::BaseButton>) |
| 13 | + @extends gtk::Widget, gtk::Button; |
| 14 | +} |
| 15 | + |
| 16 | +impl BaseButton { |
| 17 | + pub fn new() -> Self { |
| 18 | + glib::Object::new(&[]).expect("Failed to create BaseButton") |
| 19 | + } |
| 20 | +} |
| 21 | + |
| 22 | +impl Default for BaseButton { |
| 23 | + fn default() -> Self { |
| 24 | + Self::new() |
| 25 | + } |
| 26 | +} |
| 27 | + |
| 28 | +/// Public trait that implements our functions for everything that derives from BaseButton |
| 29 | +pub trait BaseButtonExt { |
| 30 | + fn sync_method(&self, extra_text: Option<String>); |
| 31 | + fn async_method(&self) -> PinnedFuture; |
| 32 | +} |
| 33 | + |
| 34 | +/// We call into imp::BaseButton_$method_name for each function. These will retrieve the |
| 35 | +/// correct class (the base class for the BaseButton or the derived class for DerivedButton) |
| 36 | +/// and call the correct implementation of the function. |
| 37 | +impl<O: IsA<BaseButton>> BaseButtonExt for O { |
| 38 | + fn sync_method(&self, extra_text: Option<String>) { |
| 39 | + unsafe { imp::base_button_sync_method(self.upcast_ref::<BaseButton>(), extra_text) } |
| 40 | + } |
| 41 | + |
| 42 | + fn async_method(&self) -> PinnedFuture { |
| 43 | + unsafe { imp::base_button_async_method(self.upcast_ref::<BaseButton>()) } |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +/// The BaseButtonImpl that each derived private struct has to implement. See derived_button/imp.rs for how |
| 48 | +/// to override functions. |
| 49 | +pub trait BaseButtonImpl: ButtonImpl + ObjectImpl + 'static { |
| 50 | + fn sync_method(&self, obj: &BaseButton, extra_text: Option<String>) { |
| 51 | + self.parent_sync_method(obj, extra_text) |
| 52 | + } |
| 53 | + |
| 54 | + fn async_method(&self, obj: &BaseButton) -> PinnedFuture { |
| 55 | + self.parent_async_method(obj) |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +pub trait BaseButtonImplExt: ObjectSubclass { |
| 60 | + fn parent_sync_method(&self, obj: &BaseButton, extra_text: Option<String>); |
| 61 | + fn parent_async_method(&self, obj: &BaseButton) -> PinnedFuture; |
| 62 | +} |
| 63 | + |
| 64 | +impl<T: BaseButtonImpl> BaseButtonImplExt for T { |
| 65 | + fn parent_sync_method(&self, obj: &BaseButton, extra_text: Option<String>) { |
| 66 | + unsafe { |
| 67 | + let data = Self::type_data(); |
| 68 | + let parent_class = data.as_ref().parent_class() as *mut imp::BaseButtonClass; |
| 69 | + if let Some(ref f) = (*parent_class).sync_method { |
| 70 | + f(obj, extra_text) |
| 71 | + } else { |
| 72 | + unimplemented!() |
| 73 | + } |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + fn parent_async_method(&self, obj: &BaseButton) -> PinnedFuture { |
| 78 | + unsafe { |
| 79 | + let data = Self::type_data(); |
| 80 | + let parent_class = data.as_ref().parent_class() as *mut imp::BaseButtonClass; |
| 81 | + if let Some(ref f) = (*parent_class).async_method { |
| 82 | + f(obj) |
| 83 | + } else { |
| 84 | + unimplemented!() |
| 85 | + } |
| 86 | + } |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +/// Make the BaseButton subclassable |
| 91 | +unsafe impl<T: BaseButtonImpl> IsSubclassable<T> for BaseButton { |
| 92 | + fn class_init(class: &mut glib::Class<Self>) { |
| 93 | + <gtk::Button as IsSubclassable<T>>::class_init(class.upcast_ref_mut()); |
| 94 | + |
| 95 | + let klass = class.as_mut(); |
| 96 | + klass.sync_method = Some(sync_method_trampoline::<T>); |
| 97 | + klass.async_method = Some(async_method_trampoline::<T>); |
| 98 | + } |
| 99 | + |
| 100 | + fn instance_init(instance: &mut glib::subclass::InitializingObject<T>) { |
| 101 | + <gtk::Button as IsSubclassable<T>>::instance_init(instance); |
| 102 | + } |
| 103 | +} |
| 104 | + |
| 105 | +// Virtual method implementation trampolines |
| 106 | +unsafe fn sync_method_trampoline<T>(this: &BaseButton, extra_text: Option<String>) |
| 107 | +where |
| 108 | + T: ObjectSubclass + BaseButtonImpl, |
| 109 | +{ |
| 110 | + let instance = &*(this as *const _ as *const T::Instance); |
| 111 | + let imp = instance.impl_(); |
| 112 | + imp.sync_method(this, extra_text) |
| 113 | +} |
| 114 | + |
| 115 | +unsafe fn async_method_trampoline<T>(this: &BaseButton) -> PinnedFuture |
| 116 | +where |
| 117 | + T: ObjectSubclass + BaseButtonImpl, |
| 118 | +{ |
| 119 | + let instance = &*(this as *const _ as *const T::Instance); |
| 120 | + let imp = instance.impl_(); |
| 121 | + imp.async_method(this) |
| 122 | +} |
0 commit comments