23. Objects

GObject is the fundamental type providing the common attributes and methods for all object types in GTK+, Pango and other libraries based on GObject. The GObject.GObject class provides methods for object construction and destruction, property access methods, and signal support.

This section will introduce some important aspects about the GObject implementation in Python.

23.1. Inherit from GObject.GObject

A native GObject is accessible via GObject.GObject. It is rarely instantiated directly, we generally use inherited class. A Gtk.Widget is an inherited class of a GObject.GObject. It may be interesting to make an inherited class to create a new widget, like a settings dialog.

To inherit from GObject.GObject, you must call GObject.GObject.__init__() in your constructor (if the class inherits from Gtk.Button, it must call Gtk.Button.__init__() for instance), like in the example below:

from gi.repository import GObject

class MyObject(GObject.GObject):

    def __init__(self):
        GObject.GObject.__init__(self)

23.2. Signals

Signals connect arbitrary application-specific events with any number of listeners. For example, in GTK+, every user event (keystroke or mouse move) is received from the X server and generates a GTK+ event under the form of a signal emission on a given object instance.

Each signal is registered in the type system together with the type on which it can be emitted: users of the type are said to connect to the signal on a given type instance when they register a function to be invoked upon the signal emission. Users can also emit the signal by themselves or stop the emission of the signal from within one of the functions connected to the signal.

23.2.1. Receive signals

See Main loop and Signals

23.2.2. Create new signals

New signals can be created by adding them to GObject.GObject.__gsignals__, a dictionary:

When a new signal is created, a method handler can also be defined, it will be called each time the signal is emitted. It is called do_signal_name.

class MyObject(GObject.GObject):
    __gsignals__ = {
        'my_signal': (GObject.SIGNAL_RUN_FIRST, None,
                      (int,))
    }

    def do_my_signal(self, arg):
        print("method handler for `my_signal' called with argument", arg)

GObject.SIGNAL_RUN_FIRST indicates that this signal will invoke the object method handler (do_my_signal() here) in the first emission stage. Alternatives are GObject.SIGNAL_RUN_LAST (the method handler will be invoked in the third emission stage) and GObject.SIGNAL_RUN_CLEANUP (invoke the method handler in the last emission stage).

The second part, None, indicates the return type of the signal, usually None.

(int,) indicates the signal arguments, here, the signal will only take one argument, whose type is int. Types of arguments required by signal are declared as a sequence, here it is a one-element tuple.

Signals can be emitted using GObject.GObject.emit():

my_obj.emit("my_signal", 42) # emit the signal "my_signal", with the
                             # argument 42

23.3. Properties

One of GObject’s nice features is its generic get/set mechanism for object properties. Each class inherited from GObject.GObject can define new properties. Each property has a type which never changes (e.g. str, float, int…). For instance, they are used for Gtk.Button where there is a “label” property which contains the text of the button.

23.3.1. Use existing properties

The class GObject.GObject provides several useful functions to manage existing properties, GObject.GObject.get_property() and GObject.GObject.set_property().

Some properties also have functions dedicated to them, called getter and setter. For the property “label” of a button, there are two functions to get and set them, Gtk.Button.get_label() and Gtk.Button.set_label().

23.3.2. Create new properties

A property is defined with a name and a type. Even if Python itself is dynamically typed, you can’t change the type of a property once it is defined. A property can be created using GObject.Property.

from gi.repository import GObject

class MyObject(GObject.GObject):

    foo = GObject.Property(type=str, default='bar')
    property_float = GObject.Property(type=float)
    def __init__(self):
        GObject.GObject.__init__(self)

Properties can also be read-only, if you want some properties to be readable but not writable. To do so, you can add some flags to the property definition, to control read/write access. Flags are GObject.ParamFlags.READABLE (only read access for external code), GObject.ParamFlags.WRITABLE (only write access), GObject.ParamFlags.READWRITE (public):

foo = GObject.Property(type=str, flags = GObject.ParamFlags.READABLE) # not writable
bar = GObject.Property(type=str, flags = GObject.ParamFlags.WRITABLE) # not readable

You can also define new read-only properties with a new method decorated with GObject.Property:

from gi.repository import GObject

class MyObject(GObject.GObject):

    def __init__(self):
        GObject.GObject.__init__(self)

    @GObject.Property
    def readonly(self):
        return 'This is read-only.'

You can get this property using:

my_object = MyObject()
print(my_object.readonly)
print(my_object.get_property("readonly"))

The API of GObject.Property is similar to the builtin property(). You can create property setter in a way similar to Python property:

class AnotherObject(GObject.Object):
    value = 0

    @GObject.Property
    def prop(self):
        'Read only property.'
        return 1

    @GObject.Property(type=int)
    def propInt(self):
        'Read-write integer property.'
        return self.value

    @propInt.setter
    def propInt(self, value):
        self.value = value

There is also a way to define minimum and maximum values for numbers, using a more verbose form:

from gi.repository import GObject

class MyObject(GObject.GObject):

    __gproperties__ = {
        "int-prop": (int, # type
                     "integer prop", # nick
                     "A property that contains an integer", # blurb
                     1, # min
                     5, # max
                     2, # default
                     GObject.ParamFlags.READWRITE # flags
                    ),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        self.int_prop = 2

    def do_get_property(self, prop):
        if prop.name == 'int-prop':
            return self.int_prop
        else:
            raise AttributeError('unknown property %s' % prop.name)

    def do_set_property(self, prop, value):
        if prop.name == 'int-prop':
            self.int_prop = value
        else:
            raise AttributeError('unknown property %s' % prop.name)

Properties must be defined in GObject.GObject.__gproperties__, a dictionary, and handled in do_get_property and do_set_property.

23.3.3. Watch properties

When a property is modified, a signal is emitted, whose name is “notify::property-name”:

my_object = MyObject()

def on_notify_foo(obj, gparamstring):
    print("foo changed")

my_object.connect("notify::foo", on_notify_foo)

my_object.set_property("foo", "bar") # on_notify_foo will be called

Note that you have to use the canonical property name when connecting to the notify signals, as explained in GObject.Object.signals.notify(). For instance, for a Python property foo_bar_baz you would connect to the signal notify::foo-bar-baz using

my_object = MyObject()

def on_notify_foo_bar_baz(obj, gparamstring):
    print("foo_bar_baz changed")

my_object.connect("notify::foo-bar-baz", on_notify_foo_bar_baz)

23.4. API

class GObject.GObject
get_property(property_name)

Retrieves a property value.

set_property(property_name, value)

Set property property_name to value.

emit(signal_name, ...)

Emit signal signal_name. Signal arguments must follow, e.g. if your signal is of type (int,), it must be emitted with:

self.emit(signal_name, 42)
freeze_notify()

This method freezes all the “notify::” signals (which are emitted when any property is changed) until the thaw_notify() method is called.

It is recommended to use the with statement when calling freeze_notify(), that way it is ensured that thaw_notify() is called implicitly at the end of the block:

with an_object.freeze_notify():
    # Do your work here
    ...
thaw_notify()

Thaw all the “notify::” signals which were frozen by freeze_notify().

It is recommended to not call thaw_notify() explicitly but use freeze_notify() together with the with statement.

handler_block(handler_id)

Blocks a handler of an instance so it will not be called during any signal emissions unless handler_unblock() is called for that handler_id. Thus “blocking” a signal handler means to temporarily deactivate it, a signal handler has to be unblocked exactly the same amount of times it has been blocked before to become active again.

It is recommended to use handler_block() in conjunction with the with statement which will call handler_unblock() implicitly at the end of the block:

with an_object.handler_block(handler_id):
    # Do your work here
    ...
handler_unblock(handler_id)

Undoes the effect of handler_block(). A blocked handler is skipped during signal emissions and will not be invoked until it has been unblocked exactly the amount of times it has been blocked before.

It is recommended to not call handler_unblock() explicitly but use handler_block() together with the with statement.

__gsignals__

A dictionary where inherited class can define new signals.

Each element in the dictionary is a new signal. The key is the signal name. The value is a tuple, with the form:

(GObject.SIGNAL_RUN_FIRST, None, (int,))

GObject.SIGNAL_RUN_FIRST can be replaced with GObject.SIGNAL_RUN_LAST or GObject.SIGNAL_RUN_CLEANUP. None is the return type of the signal. (int,) is the tuple of the parameters of the signal.

__gproperties__

The __gproperties__ dictionary is a class property where you define the properties of your object. This is not the recommended way to define new properties, the method written above is much less verbose. The benefits of this method is that a property can be defined with more settings, like the minimum or the maximum for numbers.

The key is the name of the property

The value is a tuple which describe the property. The number of elements of this tuple depends on its first element but the tuple will always contain at least the following items:

The first element is the property’s type (e.g. int, float…).

The second element is the property’s nick name, which is a string with a short description of the property. This is generally used by programs with strong introspection capabilities, like the graphical user interface builder Glade.

The third one is the property’s description or blurb, which is another string with a longer description of the property. Also used by Glade and similar programs.

The last one (which is not necessarily the forth one as we will see later) is the property’s flags: GObject.PARAM_READABLE, GObject.PARAM_WRITABLE, GObject.PARAM_READWRITE.

The absolute length of the tuple depends on the property type (the first element of the tuple). Thus we have the following situations:

If the type is bool or str, the forth element is the default value of the property.

If the type is int or float, the forth element is the minimum accepted value, the fifth element is the maximum accepted value and the sixth element is the default value.

If the type is not one of these, there is no extra element.

GObject.SIGNAL_RUN_FIRST

Invoke the object method handler in the first emission stage.

GObject.SIGNAL_RUN_LAST

Invoke the object method handler in the third emission stage.

GObject.SIGNAL_RUN_CLEANUP

Invoke the object method handler in the last emission stage.

GObject.ParamFlags.READABLE

The property is readable.

GObject.ParamFlags.WRITABLE

The property is writable.

GObject.ParamFlags.READWRITE

The property is readable and writable.