Last active
December 28, 2023 05:27
-
-
Save Miqueas/9f1eec873f87cb02238bd6de2d435705 to your computer and use it in GitHub Desktop.
[Lua + GObject] Subclassing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local lgi = require("lgi") | |
local GObject = lgi.require("GObject", "2.0") | |
-- Our new class inherits directly from GObject | |
local Person = GObject.Object:derive("Person") | |
-- Class constructor, used by GObject. This function | |
-- is called one time and is for register our class. | |
-- Inside this function we can do some things like | |
-- create some properties, signals and override some | |
-- virtual functions | |
function Person:_class_init(Class) | |
-- First of all, in this context (_class_init function) | |
-- 'self' is just a normal table. But 'Class' is the | |
-- class that we're making, that mean the 'Person' class | |
-- Before create properties, is mandatory create a setter | |
-- and getter functions. That functions recieves 3 arguments: | |
-- guint property_id | |
-- const GValue *value | |
-- GParamSpec *pspec | |
-- That's how looks in C. With that arguments, we can make a | |
-- simple setter function like this: | |
function Class:set_property(id, val, pspec) | |
-- Properties id is explained below | |
if id == 1 then | |
-- 'priv' is just that, a private field where we can store | |
-- some things that we need. Like, by example, the value of | |
-- a property. In the C land this field is an struct, but | |
-- in Lua is just a table. | |
self.priv.name = val:get_string() | |
-- Also, if you try to do this: | |
-- self.name = val:get_string() | |
-- You'll get an error (C stack overflow), because generates | |
-- a call loop like this: | |
-- self.name = value ("set" operation, calls set_property function) | |
-- set_property function: | |
-- self.name = value | |
-- set_property function: | |
-- self.name = value | |
-- set_property function: | |
-- self.name = value | |
-- ... (and so on to infinity) | |
elseif id == 2 then | |
self.priv.age = val:get_uint() | |
else | |
GObject.OBJECT_WARN_INVALID_PROPERTY_ID(self, id, pspec) | |
end | |
end | |
-- A basic getter function is very similar to a setter function. | |
-- The diference is that, instead of store a value in the 'priv' | |
-- field, we sets the value of the GValue argument (here, the | |
-- argument 'const GValue *value' is 'GValue *value') using the | |
-- stored value in the 'priv' field: | |
function Class:get_property(id, val, pspec) | |
-- Properties id is explained below | |
if id == 1 then | |
val:set_string(self.priv.name) | |
elseif id == 2 then | |
val:set_uint(self.priv.age) | |
else | |
GObject.OBJECT_WARN_INVALID_PROPERTY_ID(self, id, pspec) | |
end | |
end | |
-- Creating properties is done by using the install_property() method, | |
-- that recieves 2 arguments (in C land): | |
-- guint property_id | |
-- GParamSpec *pspec | |
-- GParamSpec allows to implement some things in our properties like | |
-- the access scope (read, write, etc), data type, etc. All properties | |
-- have an id (a number) and starts from 1 (0 does nothing in both, the | |
-- C land and Lua and I don't know why) | |
Class:install_property( | |
-- Property id | |
1, | |
-- The GParamSpec for this property | |
GObject.ParamSpecString( | |
-- Canonical property name | |
"name", | |
-- A nick for the property | |
"Name", | |
-- A little description | |
"The person name", | |
-- Default value | |
"", | |
-- Access flags. Users can... | |
{ | |
-- "get" this property, | |
GObject.ParamFlags.READABLE, | |
-- "set" this property and... | |
GObject.ParamFlags.WRITABLE, | |
-- ensures that the property will | |
-- be available on the construction | |
-- of the object | |
GObject.ParamFlags.CONSTRUCT | |
} | |
) | |
) | |
Class:install_property( | |
-- Property id | |
2, | |
-- A GParamSpec | |
GObject.ParamSpecUInt( | |
-- Canonical property name | |
"age", | |
-- A nick for the property | |
"Age", | |
-- A little description | |
"The person age", | |
-- Min value | |
0, | |
-- Max value | |
1000, | |
-- Default value | |
0, | |
-- Access flags, users can... | |
{ | |
-- "get" this property, | |
GObject.ParamFlags.READABLE, | |
-- "set" this property and... | |
GObject.ParamFlags.WRITABLE, | |
-- ensures that the property will | |
-- be available on the construction | |
-- of the object | |
GObject.ParamFlags.CONSTRUCT | |
} | |
) | |
) | |
end | |
-- Object initialisation, used by the user when creates | |
-- a new instance of our class. Note that the _class_init | |
-- function is optional (in Lua, I don't know in C), so... | |
-- If you just want to have an object with some default | |
-- values, you can use this function for that | |
function Person:_init() | |
-- Here, 'self' does refer to our class 'Person' | |
-- This does not make any relevant changes. | |
-- Because these properties have the 'CONSTRUCT' | |
-- flag,we are changing them here, but when the | |
-- user creates an instance, the values are reset | |
-- to the user specified or default values. | |
self.name = "Jhon" | |
self.age = 36 | |
end | |
-- Lets try our new class! | |
local p1 = Person() | |
-- You'll see only the default values | |
print(p1.name) | |
print(p1.age) | |
-- Lets try again | |
local p2 = Person({ name = "Jhon", age = 36 }) | |
print(p2.name) | |
print(p2.age) | |
-- More details here: https://wiki.gnome.org/HowDoI/SubclassGObject |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment