GObject decorators
Decorators that wrap GObject.registerClass
.
Example Usage
import GObject, { register, property, signal } from "gjsx/gobject"
@register({ GTypeName: "MyObj" })
class MyObj extends GObject.Object {
@property(String)
declare myProp: string
@signal(String, GObject.TYPE_UINT)
declare mySignal: (a: string, b: number) => void
}
What it transpiles to
const props = Symbol("private props")
class MyObj extends GObject.Object {
[props] = { myProp: "" }
get myProp() {
return this[props].myProp
}
set myProp(value) {
if (this.myProp !== value) {
this[props].myProp = value
this.notify("my-prop")
}
}
get_my_prop() {
return this.myProp
}
set_my_prop() {
return this.myProp
}
mySignal(a, b) {
this.emit("my-signal", a, b)
}
on_my_signal(a, b) {
// default handler would go here
// which is then hooked up with registerClass
}
}
GObject.registerClass({
GTypeName: "MyObj",
Properties: {
"my-prop": GObject.ParamSpec.string(
"my-prop",
"",
"",
GObject.ParamFlags.READWRITE,
"",
),
},
Signals: {
"my-si": {
param_types: [String.$gtype, GObject.TYPE_UINT]
}
},
}, MyObj)
Property decorator
type PropertyDeclaration =
| { $gtype: GObject.GType }
| ((name: string, flags: GObject.ParamFlags) => GObject.ParamSpec)
function property(declaration: PropertyDeclaration)
The property
decorator takes one of
any class that has a registered
GType
. This includes the globally availableString
,Number
,Boolean
andObject
JavaScript constructors which are mapped to their relativeGObject.ParamSpec
.Object
:ParamSpec.jsobject
String
:ParamSpec.string
Number
:ParamSpec.double
Boolean
:ParamSpec.boolean
ts@register() class MyObj extends GObject.Object { @property(String) declare myProp: string @property(MyObj) declare myProp2: MyObj }
a function that produces a
ParamSpec
: the passed name is a kebab-cased name of the property, for examplemyProp
->my-prop
and flags is eitherParamFlags.READABLE
,ParamFlags.WRITABLE
orParamFlags.READWRITE
tsconst Percent = (name: string, flags: GObject.ParamFlags) => ( GObject.ParamSpec.double(name, "", "", flags, 0, 1, 0) ) @register() class MyObj extends GObject.Object { @property(Percent) declare percent: number }
The property decorator can be applied in the following ways:
- On a property declaration
@register()
class MyObj extends GObject.Object {
@property(String)
declare myProp: string
}
This will create a getter and setter for the property and will also emit the notify signal when the value is set to a new value.
TIP
The declare
keyword is required if the property is not set in the constructor. or if its set with super()
.
WARNING
The value is checked by reference, this is important if your property is an object type.
const dict = obj.prop
dict["key"] = 0
obj.prop = dict // This will not emit notify::prop
obj.prop = { ...dict } // This will emit notify::prop
If you want to set a custom default value, you can do so in the super
constructor of your class.
@register()
class MyObj extends GObject.Object {
@property(String)
declare myProp: string
constructor() {
super({ myProp: "default-value" } as any)
}
}
NOTE
super
is not correctly typed for this usecase however. In most cases you can just set the property after to satisfy TypeScript in which case you can also drop declare
.
@register()
class MyObj extends GObject.Object {
@property(String)
myProp: string
constructor({ myProp = "default-value" }: { myProp: string }) {
super()
this.myProp = myProp
}
}
- On a single getter or a single setter
@register()
class MyObj extends GObject.Object {
@property(String)
get readOnly() {
return "readonly value"
}
@property(String)
get writeOnly(value: string) {
// setter logic
this.notify("write-only")
}
}
This will create a read-only / write-only property.
TIP
When defining setters, notify
signal emission has to be done explicitly.
- On a getter and setter
@register()
class MyObj extends GObject.Object {
declare private _prop: string
@property(String)
get myProp () {
return "value"
}
set myProp (v: string) {
if (v !== this._prop) {
this._prop = v
this.notify("my-prop")
}
}
}
This will create a read-write property.
TIP
The decorator has to be used on either the setter or getter, but not both.
Signal decorator
function signal(...params: Array<{ $gtype: GObject.GType } | GObject.GType>)
function signal(declaration?: SignalDeclaration) // Object you would pass to GObject.registerClass
You can apply the signal decorator to either a property declaration or a method.
@register()
class MyObj extends GObject.Object {
@signal(GObject.TYPE_STRING, GObject.TYPE_STRING)
declare mySig: (a: String, b: String) => void
@signal(String, String)
mySig(a: string, b: string) {
// default signal handler
}
}
You can emit the signal by calling the signal method or using emit
.
const obj = new MyObj()
obj.connect("my-sig", (obj, a: string, b: string) => {})
obj.mySig("a", "b")
obj.emit("my-sig", "a", "b")
Register decorator
Every GObject subclass has to be registered. You can pass the same options to this decorator as you would to GObject.registerClass
@register({ GTypeName: "MyObj" })
class MyObj extends GObject.Object {
}
TIP
This decorator registers properties and signals defined with decorators, so make sure to use this and not GObject.registerClass
if you define any.