1// Take a look at the license at the top of the repository in the LICENSE file.
2
3#![allow(clippy::needless_doctest_main)]
4// rustdoc-stripper-ignore-next
5//! Module containing infrastructure for subclassing `GObject`s and registering boxed types.
6//!
7//! # Example for registering a `glib::Object` subclass
8//!
9//! The following code implements a subclass of `glib::Object` with a
10//! string-typed "name" property.
11//!
12//! ```rust
13//! use glib::prelude::*;
14//! use glib::subclass;
15//! use glib::subclass::prelude::*;
16//! use glib::{Variant, VariantType};
17//!
18//! use std::cell::{Cell, RefCell};
19//!
20//! #[derive(Debug, Eq, PartialEq, Clone, Copy, glib::Enum)]
21//! #[repr(u32)]
22//! // type_name: GType name of the enum (mandatory)
23//! #[enum_type(name = "SimpleObjectAnimal")]
24//! enum Animal {
25//! Goat = 0,
26//! #[enum_value(name = "The Dog")]
27//! Dog = 1,
28//! // name: the name of the GEnumValue (optional), default to the enum name in CamelCase
29//! // nick: the nick of the GEnumValue (optional), default to the enum name in kebab-case
30//! #[enum_value(name = "The Cat", nick = "chat")]
31//! Cat = 2,
32//! }
33//!
34//! impl Default for Animal {
35//! fn default() -> Self {
36//! Animal::Goat
37//! }
38//! }
39//!
40//! #[glib::flags(name = "MyFlags")]
41//! enum MyFlags {
42//! #[flags_value(name = "Flag A", nick = "nick-a")]
43//! A = 0b00000001,
44//! #[flags_value(name = "Flag B")]
45//! B = 0b00000010,
46//! #[flags_value(skip)]
47//! AB = Self::A.bits() | Self::B.bits(),
48//! C = 0b00000100,
49//! }
50//!
51//! impl Default for MyFlags {
52//! fn default() -> Self {
53//! MyFlags::A
54//! }
55//! }
56//!
57//! mod imp {
58//! use super::*;
59//!
60//! // This is the struct containing all state carried with
61//! // the new type. Generally this has to make use of
62//! // interior mutability.
63//! // If it implements the `Default` trait, then `Self::default()`
64//! // will be called every time a new instance is created.
65//! #[derive(Default)]
66//! pub struct SimpleObject {
67//! name: RefCell<Option<String>>,
68//! animal: Cell<Animal>,
69//! flags: Cell<MyFlags>,
70//! variant: RefCell<Option<Variant>>,
71//! }
72//!
73//! // ObjectSubclass is the trait that defines the new type and
74//! // contains all information needed by the GObject type system,
75//! // including the new type's name, parent type, etc.
76//! // If you do not want to implement `Default`, you can provide
77//! // a `new()` method.
78//! #[glib::object_subclass]
79//! impl ObjectSubclass for SimpleObject {
80//! // This type name must be unique per process.
81//! const NAME: &'static str = "SimpleObject";
82//!
83//! type Type = super::SimpleObject;
84//!
85//! // The parent type this one is inheriting from.
86//! // Optional, if not specified it defaults to `glib::Object`
87//! type ParentType = glib::Object;
88//!
89//! // Interfaces this type implements.
90//! // Optional, if not specified it defaults to `()`
91//! type Interfaces = ();
92//! }
93//!
94//! // Trait that is used to override virtual methods of glib::Object.
95//! impl ObjectImpl for SimpleObject {
96//! // Called once in the very beginning to list all properties of this class.
97//! fn properties() -> &'static [glib::ParamSpec] {
98//! use once_cell::sync::Lazy;
99//! static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
100//! vec![
101//! glib::ParamSpecString::builder("name")
102//! .build(),
103//! glib::ParamSpecEnum::builder::<Animal>("animal")
104//! .build(),
105//! glib::ParamSpecFlags::builder::<MyFlags>("flags")
106//! .build(),
107//! glib::ParamSpecVariant::builder("variant", glib::VariantTy::ANY)
108//! .build(),
109//! ]
110//! });
111//!
112//! PROPERTIES.as_ref()
113//! }
114//!
115//! // Called whenever a property is set on this instance. The id
116//! // is the same as the index of the property in the PROPERTIES array.
117//! fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
118//! match pspec.name() {
119//! "name" => {
120//! let name = value
121//! .get()
122//! .expect("type conformity checked by `Object::set_property`");
123//! self.name.replace(name);
124//! },
125//! "animal" => {
126//! let animal = value
127//! .get()
128//! .expect("type conformity checked by `Object::set_property`");
129//! self.animal.replace(animal);
130//! },
131//! "flags" => {
132//! let flags = value
133//! .get()
134//! .expect("type conformity checked by `Object::set_property`");
135//! self.flags.replace(flags);
136//! },
137//! "variant" => {
138//! let variant = value
139//! .get()
140//! .expect("type conformity checked by `Object::set_property`");
141//! self.variant.replace(variant);
142//! },
143//! _ => unimplemented!(),
144//! }
145//! }
146//!
147//! // Called whenever a property is retrieved from this instance. The id
148//! // is the same as the index of the property in the PROPERTIES array.
149//! fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
150//! match pspec.name() {
151//! "name" => self.name.borrow().to_value(),
152//! "animal" => self.animal.get().to_value(),
153//! "flags" => self.flags.get().to_value(),
154//! "variant" => self.variant.borrow().to_value(),
155//! _ => unimplemented!(),
156//! }
157//! }
158//!
159//! // Called right after construction of the instance.
160//! fn constructed(&self) {
161//! // Chain up to the parent type's implementation of this virtual
162//! // method.
163//! self.parent_constructed();
164//!
165//! // And here we could do our own initialization.
166//! }
167//! }
168//! }
169//!
170//! // Optionally, define a wrapper type to make it more ergonomic to use from Rust
171//! glib::wrapper! {
172//! pub struct SimpleObject(ObjectSubclass<imp::SimpleObject>);
173//! }
174//!
175//! impl SimpleObject {
176//! // Create an object instance of the new type.
177//! pub fn new() -> Self {
178//! glib::Object::new()
179//! }
180//! }
181//!
182//! pub fn main() {
183//! let obj = SimpleObject::new();
184//!
185//! // Get the name property and change its value.
186//! assert_eq!(obj.property::<Option<String>>("name"), None);
187//! obj.set_property("name", "test");
188//! assert_eq!(&obj.property::<String>("name"), "test");
189//!
190//! assert_eq!(obj.property::<Animal>("animal"), Animal::Goat);
191//! obj.set_property("animal", Animal::Cat);
192//! assert_eq!(obj.property::<Animal>("animal"), Animal::Cat);
193//!
194//! assert_eq!(obj.property::<MyFlags>("flags"), MyFlags::A);
195//! obj.set_property("flags", MyFlags::B);
196//! assert_eq!(obj.property::<MyFlags>("flags"), MyFlags::B);
197//! }
198//! ```
199//!
200//! # Example for registering a boxed type for a Rust struct
201//!
202//! The following code boxed type for a tuple struct around `String` and uses it in combination
203//! with `glib::Value`.
204//!
205//! ```rust
206//! use glib::prelude::*;
207//! use glib::subclass;
208//! use glib::subclass::prelude::*;
209//!
210//! #[derive(Clone, Debug, PartialEq, Eq, glib::Boxed)]
211//! #[boxed_type(name = "MyBoxed")]
212//! struct MyBoxed(String);
213//!
214//! pub fn main() {
215//! assert!(MyBoxed::static_type().is_valid());
216//!
217//! let b = MyBoxed(String::from("abc"));
218//! let v = b.to_value();
219//! let b2 = v.get::<&MyBoxed>().unwrap();
220//! assert_eq!(&b, b2);
221//! }
222//! ```
223
224pub mod basic;
225#[macro_use]
226pub mod types;
227
228#[macro_use]
229pub mod interface;
230
231#[macro_use]
232pub mod object;
233
234#[macro_use]
235pub mod boxed;
236
237pub mod shared;
238
239pub mod signal;
240
241mod object_impl_ref;
242pub use object_impl_ref::{ObjectImplRef, ObjectImplWeakRef};
243
244pub mod prelude {
245 // rustdoc-stripper-ignore-next
246 //! Prelude that re-exports all important traits from this crate.
247 pub use super::{
248 boxed::BoxedType,
249 interface::{ObjectInterface, ObjectInterfaceExt, ObjectInterfaceType},
250 object::{DerivedObjectProperties, ObjectClassSubclassExt, ObjectImpl, ObjectImplExt},
251 shared::{RefCounted, SharedType},
252 types::{
253 ClassStruct, InstanceStruct, InstanceStructExt, IsImplementable, IsSubclassable,
254 IsSubclassableExt, ObjectSubclass, ObjectSubclassExt, ObjectSubclassIsExt,
255 ObjectSubclassType,
256 },
257 };
258}
259
260pub use self::{
261 boxed::register_boxed_type,
262 interface::register_interface,
263 signal::{
264 Signal, SignalClassHandlerToken, SignalId, SignalInvocationHint, SignalQuery, SignalType,
265 },
266 types::{register_type, InitializingObject, InitializingType, TypeData},
267};
268