Search code examples
gtkpygtk

Difference between connect() and connect_after() in pygtk


I don't know what are Differences between connect() and connect_after() in pygtk. can someone explain this with an example code.

Thanks.


Solution

  • First, here is the definition for g_signal_connect_after:

    Connects a GCallback function to a signal for a particular object.The handler will be called after the default handler of the signal.

    But what is the default handler you may ask, well, the GSignal description it's very descritive:

    The basic concept of the signal system is that of the emission of a signal. Signals are introduced per-type and are identified through strings. Signals introduced for a parent type are available in derived types as well, so basically they are a per-type facility that is inherited.

    A signal emission mainly involves invocation of a certain set of callbacks in precisely defined manner. There are two main categories of such callbacks, per-object ones and user provided ones. (Although signals can deal with any kind of instantiatable type, I'm referring to those types as "object types" in the following, simply because that is the context most users will encounter signals in.) The per-object callbacks are most often referred to as "object method handler" or "default (signal) handler", while user provided callbacks are usually just called "signal handler".

    The object method handler is provided at signal creation time (this most frequently happens at the end of an object class' creation), while user provided handlers are frequently connected and disconnected to/from a certain signal on certain object instances.

    A signal emission consists of five stages, unless prematurely stopped:

    • Invocation of the object method handler for G_SIGNAL_RUN_FIRST signals

    • Invocation of normal user-provided signal handlers (where the after flag is not set)

    • Invocation of the object method handler for G_SIGNAL_RUN_LAST signals

    • Invocation of user provided signal handlers (where the after flag is set)

    • Invocation of the object method handler for G_SIGNAL_RUN_CLEANUP signals

    The user-provided signal handlers are called in the order they were connected in.

    Now that you know the signal sequence, what follows is the answer to a similar question but on the Gtk mailing list:

    g_signal_connect_after will let you run your user handler after the class's default handler; why is this usefull ?

    Say I have an object that emits an "initialize" signal in which its class handler does the work, you probably want your handler to run after the class handler so that you can use the already initialized object in your function.

    I think normally you dont have to use this method because signals of that nature are usually installed with G_SIGNAL_RUN_FIRST which; if I'm not mistaken means that it's default handler will be called before user handlers anyway.

    Using it on higher level languages may not have an obvious need but, eg., lets say that you want to guarantee that a callback will be the last user callback to run, then you can use this method. (Note pygtk is deprecated, use pygobject).

    A simple example where we connect two methods, on_click2 and on_click1 (by this order), by using connect_after for on_click2 we make sure that it will run last (user callbacks):

    import gi
    gi.require_version("Gtk", "3.0")
    from gi.repository import Gtk
    
    class Button(Gtk.Box):
    
        def __init__(self, message):
            Gtk.Box.__init__(self, spacing=6)
            self.set_border_width(10)
            button = Gtk.Button.new_with_label(message)
            self.pack_start(button, True, True, 0)
            button.connect_after("clicked", self.on_click2)
            button.connect("clicked", self.on_click1)
    
        def on_click1(self, widget):
            print ("Click1 signal. connect normal");
    
        def on_click2(self, widget):
            print ("Click2 signal. connect after");
    
    win = Gtk.Window()
    button = Button("Test")
    
    win.add (button)
    
    win.connect("destroy", Gtk.main_quit)
    win.show_all()
    
    Gtk.main()
    

    And the result is that on_click2 is the last to be called despite the fact it was the first connected:

    $ python <filename.py>
    ... (Click test button)...
    Click1 signal. connect normal
    Click2 signal. connect after
    

    enter image description here