Skip to content

Instantly share code, notes, and snippets.

@Miqueas
Last active December 28, 2023 05:27
Show Gist options
  • Save Miqueas/9f1eec873f87cb02238bd6de2d435705 to your computer and use it in GitHub Desktop.
Save Miqueas/9f1eec873f87cb02238bd6de2d435705 to your computer and use it in GitHub Desktop.
[Lua + GObject] Subclassing
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