WebKitGTK’s introspected Python bindings exposed the DOM but left out its event-listener methods. The scanner warned that callback scope annotations were missing and marked the methods non-introspectable. I needed events for the PyJS desktop work, so I started following the path from Python into WebKit and back.
Bug 77835 contains that investigation, several people’s patches, and a long sequence of things I thought might be enough. Adding an annotation made a method visible. It did not, by itself, make the interface correct.
Type
The generic callback type erased information the language binding needed. GCallback was a function pointer returning void and taking no declared arguments. WebKit knew how it intended to call the function, but that knowledge did not automatically survive into the generated introspection description.
Callbacks could fire in Python without receiving the event arguments. Zan’s investigation and working patch helped separate that failure from the initial visibility problem. I then posted an experiment using a type annotation to supply the more specific callback signature without changing every C declaration.
That got arguments through. Removing the listener still failed.
Lifetime
A listener usually outlives the call that registers it and may fire more than once. A scope meaning “during this call” or “until the first callback” could not express that lifetime faithfully.
The binding needed a way to retain the callable and learn when it could be released. Discussion covered a destroy-notification argument and fuller API variants, following patterns already used elsewhere in GObject. Merely choosing an annotation that quieted the scanner would have left ownership unexplained.
Identity
Removal had another requirement: it had to refer to the listener previously registered. Looking up a Python bound method again could produce a different method object, and marshaling a callable again could create another native callback wrapper. The same-looking Python expression did not guarantee the same native listener identity.
I tried dedicated callback objects, retained references, and eventually closures allocated on the C side and passed back through Python. A GClosure could carry the callback and its associated state while giving both registration and removal an object to refer to.
In the thread I described walking the complete Python-to-WebKit-to-Python call chain, rebuilding libraries with debug symbols, and finally getting removal to work. The resulting patches still had design, ownership, testing, and compatibility problems.
What landed
Carlos Garcia Campos returned to the problem the following year with add_event_listener_with_closure and remove_event_listener_with_closure. The new entry points accepted closures and were exposed to introspection bindings under the ordinary listener names. The existing public C entry points remained available.
Gustavo Noronha Silva reviewed the change, and Carlos landed it. I had supplied the initial report, tracing, experiments, and earlier patches; Carlos wrote the final change.