GObject
Before jumping into Gtk, you have to understand a few concepts about GObject.Object
which is the base type everything inherits from.
GObject Construction
TIP
In rare cases, like the Gio.File
interface, objects can not be constructed with the new
operator and a constructor method must always be used.
The most common way to create a GObject instance is using the new
operator. When constructing a GObject this way, you can pass a dictionary of properties:
const labelWidget = new Gtk.Label({
label: "<b>Text</b>",
useMarkup: true,
})
Many classes also have static constructor methods you can use directly:
const labelWidget = Gtk.Label.new("Text")
Signals
GObjects support a signaling system, similar to events and EventListeners in the JavaScript Web API. Here we will cover the basics of connecting and disconnection signals, as well as using callbacks.
Connecting Signals
Signals are connected by calling GObject.Object.prototype.connect()
, which returns a handler ID. Signals are disconnected by passing that ID to GObject.Object.prototype.disconnect()
:
const label = Gtk.Label.new("Lorem Ipsum")
// Connecting a signal
const handlerId = label.connect("copy-clipboard", () => {
console.log(`Copied "${label.label}" to clipboard!`)
})
// Disconnecting a signal
label.disconnect(handlerId)
Callback Arguments
Signals often have multiple callback arguments, but the first is always the emitting object:
const selectLabel = Gtk.Label.new("")
selectLabel.connect("move-cursor", (label, step, count, extendSelection) => {
if (label === selectLabel) {
console.log("selectLabel emitted the signal!")
}
if (step === Gtk.MovementStep.WORDS) {
console.log(`The cursor was moved ${count} word(s)`)
}
if (extendSelection) {
console.log("The selection was extended")
}
})
Callback Return Values
WARNING
A callback with no return value will implicitly return undefined
, while an async
function will implicitly return a Promise
.
Some signals expect a return value, usually a boolean
. The type and behavior of the return value will be described in the documentation for the signal.
const linkLabel = new Gtk.Label({
label: '<a href="https://www.gnome.org">GNOME</a>',
use_markup: true,
})
linkLabel.connect("activate-link", (label, uri) => {
if (uri.startsWith("file://")) {
console.log(`Ignoring ${uri}`)
return true
}
return false
})
Using an async
function as a signal handler will return an implicit Promise
, which will be coerced to a truthy value. If necessary, use a traditional Promise
chain and return the expected value type explicitly.
linkLabel.connect("activate-link", (label, uri) => {
// Do something asynchronous with the signal arguments
Promise.resolve(uri).catch(console.error)
return true
})
Properties
GObject supports a property system that is slightly more powerful than native JavaScript properties.
Accessing Properties
GObject properties may be retrieved and set using native property style access or GObject get and set methods.
const invisibleLabel = new Gtk.Label({
visible: false,
})
let visible
// Three different ways to get or set properties
visible = invisibleLabel.visible
visible = invisibleLabel["visible"]
visible = invisibleLabel.get_visible()
invisibleLabel.visible = false
invisibleLabel["visible"] = false
invisibleLabel.set_visible(false)
GObject property names have a canonical form that is kebab-cased
, however they are accessed differently depending on the situation:
const markupLabel = new Gtk.Label({
label: "<i>Italics</i>",
use_markup: true,
})
let useMarkup
// If using native accessors, you can use `underscore_case` or `camelCase`
useMarkup = markupLabel.use_markup
useMarkup = markupLabel.useMarkup
// Anywhere the property name is a string, you must use `kebab-case`
markupLabel["use-markup"] = true
markupLabel.connect("notify::use-markup", () => {})
// Getter and setter functions are always case sensitive
useMarkup = markupLabel.get_use_markup()
markupLabel.set_use_markup(true)
Property Change Notification
Most GObject properties will emit GObject.Object::notify
signal when the value is changed. You can connect to this signal in the form of notify::property-name
to invoke a callback when it changes:
const changingLabel = Gtk.Label.new("Original Label")
const labelId = changingLabel.connect("notify::label", (object, _pspec) => {
console.log(`New label is "${object.label}"`)
})